Using pipe(): How do I allow multiple child proces

2019-08-13 21:59发布

问题:

I'm using pipe() to split up a file by index, send that index to child processes, have the child process calculate the sum of the numbers in its designated block of the file, and return its sum to the parent.

My children seem to execute in order, where I would like them to execute at the same time to make this process more efficient.

Here's the code I'm working with:

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

int main(int argc, char *argv[])
{
int numchild;
struct timeval stop, start;
int i, j, len, ret, fpos=0, val, count=0, total=0, alltotal=0;
pid_t pid;
int nums = 1000;
FILE * file;

printf("How many children to use: ");
scanf("%d", &numchild);
printf("\nWill use %d child process(es).\n", numchild);

gettimeofday(&start, NULL);
int fd[numchild][2]; //parent to child. one for each
int results[2]; //all children to parent
pipe(results);

fd_set result_fd;
FD_ZERO(&result_fd);
FD_SET(results[0], &result_fd);
struct timeval tm = {.tv_sec=0, .tv_usec=1};

// create all pipes
for (i=0; i<numchild; i++)
{
    pipe(fd[i]);
}

for (i=0; i<numchild; i++)
{
    if((pid = fork()) == 0) // child process
    {
        pid = getpid();

        // read from parent
        len = read(fd[i][0], &fpos, sizeof(fpos));
        if (len > 0)
        {
            file = fopen("file1.dat", "r");
            fseek (file, fpos, SEEK_SET);
            count = 0;
            total = 0;

            printf("Child(%d): Recieved position: %d\n", pid, fpos);

            // read from file starting at fpos
            // add values read to a total value
            while (count < (nums/numchild))
            {
                fscanf(file, "%i", &val);
                total += val;
                count++;
            }
            //write to parent
            write(results[1], &total, sizeof(total));
            printf("Child(%d): Sent %d to parent.\n", pid, total);
        }
        else
        {
            printf("Child(%d): Error with len\n", pid);
        }
        _exit(0);
    }

    // parent process
    pid = getpid();

    fpos = ((i*nums*5)/numchild); // 5 is the offset of the file values

    // write to child process
    printf("Parent(%d): Sending file position to child\n", pid);
    write(fd[i][1], &fpos, sizeof(fpos));

    // wait for child responce
    ret = select(FD_SETSIZE+1, &result_fd, NULL, NULL, NULL); //&tm
    if (FD_ISSET(results[0], &result_fd))
    {
        ret = read(results[0], &total, sizeof(total));

        // output total
        printf("Parent(%d): Recieved %d from child.\n", pid, total);
        alltotal += total;
        //printf("\tParent(%d): Total: %d\n", pid, alltotal);
    }
}
wait(0);
gettimeofday(&stop, NULL);
printf("\tTime elapsed: %lu microseconds\n", stop.tv_usec - start.tv_usec);
printf("\tParent(%d): Total: %d\n", pid, alltotal);
}

Please let me know what I need to change to have the child processes run simultaneously (not wait to run at the exact same time, but run as soon as the parent gives them their index, instead of waiting for the previous child to complete).

回答1:

From the comments above, I conclude that: 1. this is an assignment of some type 2. it requires using fork and pipe If I were doing something like this for real (and it's not clear that it would be worth doing), I would probably be using threads queues and semaphores.

Given the constraints, I'll try to answer your question.

The problem is that you are have the parent code inside the for loop. So what is happening is that each time through the loop, the parent is spawning a child, then sending the offset information, then waiting for the result. So that forces the child to complete before the parent goes through the next iteration of the loop.

The answer is to have more than one loop. In the first loop, spawn all of the children. In the second loop, send the children their offsets. In the third loop, collect the results. In the fourth loop wait for the children to terminate. It would probably be faster if you sent the children their offsets in the first loop.

Another way to do this is to set the offset in a variable prior to doing each fork. That would obviate the need to use pipes for the input. I believe that you could also have each child just exit with the sum. Then the return exit status of the child could be the sum. The parent could just total the sums and you avoid using a return pipe. That would be a better way to do this -- though it wouldn't follow your apparent rules.



标签: c pipe fork