使用pipe():如何允许多个子进程同时执行

时间:2016-03-12 01:19:30

标签: c pipe fork

我正在使用pipe()按索引拆分文件,将该索引发送到子进程,让子进程计算文件指定块中数字的总和,并将其总和返回给父母。

我的孩子似乎按顺序执行,我会喜欢他们同时执行以使这个过程更有效率。

这是我正在使用的代码:

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

请告诉我需要更改的内容,让子进程同时运行(不要等到同一时间运行,而是在父进程为其提供索引时运行,而不是等待前一个子进程完成)。

1 个答案:

答案 0 :(得分:1)

从上述评论中我得出结论:  1.这是某种类型的任务  2.它需要使用 如果我真的做了这样的事情(并且不清楚它是否值得做),我可能会使用线程队列和信号量。

鉴于有限制,我会尽力回答你的问题。

问题是你在for循环中有父代码。所以发生的事情是,每次通过循环,父进程产生一个子进程,然后发送偏移量信息,然后等待结果。因此,在父进行下一次循环迭代之前强制子进程完成。

答案是有多个循环。在第一个循环中,生成所有子项。在第二个循环中,向孩子发送他们的偏移量。在第三个循环中,收集结果。在第四个循环中等待孩子终止。如果你在第一个循环中向孩子们发送他们的偏移量,那可能会更快。

另一种方法是在执行每个之前在变量中设置偏移量。这样可以避免使用管道进行输入。我相信你也可以让每个孩子一起退出。那么孩子的返回退出状态可以是总和。父母可以只计算总和,并避免使用返回管道。这将是更好的方式 - 虽然它不会遵循你明显的规则。