如何在C中创建临时缓冲区?

时间:2017-11-25 12:46:47

标签: c linux operating-system printf system-calls

我正在我的程序中执行一些物理计算,其中输出需要存储到临时缓冲区并通过管道。

缓冲区需要共享不同的数据类型:首先,我需要存储我正在研究的主题的名称;其次是我的计算结果(所有float数字)。

代码如下所示:

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;
}

但是,如果我使用sprintf,输出会有所不同。例如,对于M = 2,输出应为:

案例1:否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

案例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

'短跑'有什么问题?为什么这条线搞砸整个程序?

编辑:该计划是一个简单的飙车模拟器,M车在1000米直线上竞争。 master进程创建M个随机汽车(但此功能未正确实现),并通过单个管道将存储在.dat文件中的一些数据传递给M个子进程。

每辆车都是一个儿童过程,并且在其中进行计算。获取值后,每个子项都会将存储在临时缓冲区中的数据通过自己的管道传递给一个 results进程,该进程将它们存储在输出文件中。请注意,此功能仍未实现,因为首先我需要设法创建缓冲区。我的问题是关于缓冲区问题。

enter image description here

2 个答案:

答案 0 :(得分:1)

当您fork时,您创建了一个新流程。在没有任何类型的同步的情况下,创建的两个子进程同时运行。因此,每个子节点的输出可以彼此交错,这取决于OS如何决定调度每个进程。 sprintf的存在不会改变这一点。

您可能需要通过管道传递消息,以使进程彼此同步,以控制每个进程的打印时间。

答案 1 :(得分:0)

char tempBuffer[50];初始化为50而不是34,这是我发送的数据的确切大小。