xvlaze
xvlaze

Reputation: 869

How can I create a temporary buffer in C?

I am performing some physical calculations in my program, in which the output needs to be stored into a temporary buffer and passed through a pipe.

The buffer needs to share different data types: firstly, I need to store the name of the subject I'm studying; secondly the results of my calculations (all float numbers).

The code looks like this:

initialdata.dat

Aston Martin Vantage V12|07.7|090
Ferrari LaFerrari       |09.6|111
Lamborghini Aventador   |09.6|097
Porsche 911 Turbo S     |09.6|092
Tesla Model S P100D     |10.0|069
Hennessey Venom GT      |10.3|120
Bugatti Chiron          |11.2|114
Koenigsegg Agera        |10.3|121

Main.c:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <string.h>
#include <time.h>
#include <math.h>

#define READ  0
#define WRITE 1
#define M 2 // Number of subjects.

int main(){
    int pipeToChild[2];
    if (pipe(pipeToChild) < 0) {
        fprintf(stderr,"Error in pipe!");
        return -1;
    }

    pid_t pid[M];
    srand (time(NULL));

  // Declares the file pointer with the information.
    FILE * pFile;
    char buffer[34]; // Buffer where subject info is sent to childs.
    char tempBuffer[50]; // The buffer that causes problems.
    pFile = fopen ("initialdata.dat","r");

    for(int i = 0; i < M; i++){
        pid[i] = fork();
        if (pid[i] < 0){
            printf("Fork error!\n");
            return -1;
        }
        else if(pid[i]==0){ 
            // Creates the pipes (one per child) to pass the temporary buffer to the results process (still not created).
            int pipeToResults[2];
            if (pipe(pipeToResults) < 0) {
                fprintf(stderr,"Error in pipe!");
                return -1;
            }

            // Receives the car information from the file through a pipe.
            char receivedValue[34];
            receivedValue[33] = '\0';
            close(pipeToChild[WRITE]);
            read(pipeToChild[READ], receivedValue, sizeof(receivedValue));

        // Processes the information and tokenizes it.
            char name[25];
            char CHARacceleration[6];
            char CHARmaxSpeed[4];
            strcpy(name, strtok(receivedValue, "|"));
            strcpy(CHARacceleration, strtok(NULL, "|"));
            strcpy(CHARmaxSpeed, strtok(NULL, "|"));    
            float acceleration = atof(CHARacceleration);
            float maxSpeed = atoi(CHARmaxSpeed);

            // Adds 0.0X to acceleration.
            float randomNum = rand() % 5;
            acceleration = acceleration + randomNum/100;

            float distance = 0;
            float TA = 0; // Time using Uniformly Accelerated Linear Motion.
            float TB = 0; // Time using Linear Motion.
            float TE = 0.5; // Time increment.
            float currentVelocity = 0; // In m/s.

            // Applies different physical calculations depending on the case.
            while (distance <= 1000){
                TA += TE;
                if (currentVelocity < maxSpeed){ // Acceleration > 0
                    distance = (acceleration*pow((TA),2))/2;
                    currentVelocity = acceleration*TA;
                    distance = 2*distance;
                }
                else{ // Acceleration = 0
                    TB += TE;
                    currentVelocity = maxSpeed;
                    distance += maxSpeed*TB;
                }
            }

            // Debug purposes, just for ensuring everything gets processed the right way.
            printf("Name: %s\n", name);
            printf("Distance: %.2f m\n", distance);
            printf("Time: %.2f s\n", TA+TB);
            printf("Max speed reached: %.2f km/h\n", currentVelocity*3.6);
            printf("Acceleration: %.2f m/s^2\n", acceleration);
            printf("\n");

        // Comment this if you want to switch between the situations I talked about.
        sprintf(tempBuffer, "%s %.2f %.2f %.2f %.2f", name, distance, TA+TB, currentVelocity, acceleration);
            printf("Buffer: %s\n\n", tempBuffer);
            exit(0);
        }
        else if(pid[i]>0){
            // Generates a random subject from the list. Buggy section, fixed it the best way I could.
            int randCar = rand() % 15 + 1;
            if (randCar % 2 == 0)
                randCar--;
            for (int i = 1; i <= randCar; i++){
                if (pFile != NULL)
                    fgets (buffer, sizeof(buffer), pFile);
                else
                    perror ("ERROR reading file!");
            }
            char toSend[34]; //This will be passed through the `pipeToChild` pipe.
            strcpy(toSend, buffer);

            // Loads pipe.
            close(pipeToChild[READ]); 
            write(pipeToChild[WRITE], toSend, strlen(toSend));
            close(pipeToChild[WRITE]);
        }
    }
    for (int i=0;i<M;i++){
        waitpid(pid[i], NULL, 0);
    }
    fclose(pFile);
    return 0;
}

The output, though, is different depending if I use the sprintf or not. For example, for M=2, the output should be:

Case 1: No sprintf:

I'm the child process 1 with PID 12304
Name: Bugatti Chiron          
Distance: 1012.61 m
Time: 9.50 s
Max speed reached: 383.72 km/h
Aceleration: 11.22 m/s^2

I'm the child process 2 with PID 12305
Name: Bugatti Chiron          
Distance: 1012.61 m
Time: 9.50 s
Max speed reached: 383.72 km/h
Aceleration: 11.22 m/s^2

Case 2: sprintf:

I'm the child process 2 with PID 12307
I'm the child process 1 with PID 12306
Name: Bugatti Chiron          
Distance: 1012.61 m
Time: 9.50 s
Max speed reached: 383.72 km/h
Aceleration: 11.22 m/s^2
Buffer: Bugatti Chiron    1012.61 9.50 383.82 11.22

What's the problem with 'sprinting'? Why is this line screwing the whole program?

EDIT: The program is a simple drag racing simulator, where M cars compete in a 1000m straight line. The master process creates M random cars (this function is not correctly implemented, though) and passes some data stored in the .dat file to M child processes through a single pipe.

Every car is a child process, and it's within it where the calculations are made. Once we get the values, every child passes the data stored in a temporary buffer through its own pipe to one results process which stores them in an output file. Note that this function is still not implemented because first I need to manage to create the buffer. My question is only about the buffer issue.

enter image description here

Upvotes: 0

Views: 1975

Answers (2)

xvlaze
xvlaze

Reputation: 869

char tempBuffer[50]; was initialized to 50 instead of 34, which is the exact size of the data I sent.

Upvotes: 0

dbush
dbush

Reputation: 224982

When you fork, you create a new process. Without any type of synchronization, the two child processes that get created run at the same time. So the output of each child may be interleaved with each other, depending on how the OS decided to schedule each of the processes. The presence of the sprintf doesn't change that.

You'll probably need to pass messages over pipes to get the processes to sync with each other to control when each of them prints.

Upvotes: 1

Related Questions