首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >多工序管道

多工序管道
EN

Stack Overflow用户
提问于 2015-10-05 02:45:09
回答 3查看 2.2K关注 0票数 2

目前正在做一些家庭作业,并有一个困难的时间。其目标是生成10万个数字,并通过将工作划分为10个过程(每个进程10,000个数字)将它们全部相加。

我想我已经知道了如何分叉进程(希望如此),但是使用管道()来传递来自每个子进程的小计是行不通的.下面的程序为每个子进程返回44901,对于正在运行的进程返回449010。

我正在努力奋斗,但我觉得这是一件简单的事情,我应该能够理解。

代码语言:javascript
复制
main()
{
    int i;
    pid_t pid;
    int status = 0;
    int fd[2];
    int runningTotal = 0;
    pipe(fd);

    int t;
    int r;

    for (i = 0; i < 10; i++) {
        pid = fork();
        if (pid == 0){
            close(fd[0]);
            t = ChildProcess();
            write(fd[1], &t, sizeof(t));
            exit(0);
        }
        close(fd[1]);
        read(fd[0], &r, sizeof(r));
        runningTotal = runningTotal + r;
        wait(&status);
    }

    printf("%i\n", runningTotal);
}

int ChildProcess() {
    int i;
    int total = 0;
    int r = 0;

    for (i = 0; i < 10000; i++) {
        r = rand() % 10; // 0 to 10
        total = total + r;
    }

    printf("%i\n", total);
    return total;
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-10-05 03:13:33

通常,我们会为每个子程序使用一个单独的管道,否则父进程就不可能知道它读取的数据来自哪个进程。我不认为在这个特殊的情况下这是什么问题,因为在这里,你实际上并不在乎。虽然这仍然让我有些畏缩,但我认为你确实可以用一根管子来完成这个特定的任务。

事实上,我认为你的问题根本不在于管道。是和rand()一起的。所有子进程都计算完全相同的(伪随机数)序列,因为它们都使用相同的(默认)种子。如果您想要生成不同的数字序列,那么您需要在每个子进程中调用srand(),在每个子进程中给出不同的种子。rand()将生成的数字序列完全由其起始的种子决定。

请注意,如果系统的随机数生成器是好的,那么所有由不同进程计算出来的总和都应该非常接近,并且与您报告的结果非常接近。这是统计中的中心极限定理的结果,但是你可以简单地把它看作是平衡小的结果的更大的结果。在计算剩余的mod 10时可能会产生轻微的偏差。

票数 3
EN

Stack Overflow用户

发布于 2015-10-05 03:12:01

初步诊断

如果您关心的是这些子元素都生成相同的值,那么问题是它们都使用相同的随机序列,因为您没有在任何地方调用srand()。你需要把它叫做once per child,每个孩子都有一个不同的种子。

它并不是100%可靠的,但是您可能可以在每个子程序中使用srand(time(0) + getpid()); --甚至只是getpid(),因为这些值肯定是不同的。

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

int ChildProcess(void)
{
    int total = 0;
    srand(time(0) + getpid());

    for (int i = 0; i < 10000; i++)
    {
        int r = rand() % 10; // 0 to 9 (not 10).
        total = total + r;
    }

    printf("%i\n", total);
    return total;
}

进一步审查

实际上,仔细检查一下,还有另外一个问题。父进程在分叉第一个子进程之后关闭管道的写端,因此后续的子进程没有可用的文件描述符。读取的值将永远是第一个子代的值。所以,你需要做更认真的工作。

代码语言:javascript
复制
int main(void)
{
    int fd[2];
    pipe(fd);  // Missing error check

    for (int i = 0; i < 10; i++) {
        pid_t pid = fork();
        if (pid == 0){
            close(fd[0]);
            int t = ChildProcess();
            write(fd[1], &t, sizeof(t));  // Missing error check?
            exit(0);
        }
        // Print PID here?  Error check?
    }

    close(fd[1]);

    int r;
    int runningTotal = 0;
    while (read(fd[0], &r, sizeof(r)) > 0)  // Debugging opportunities here
        runningTotal = runningTotal + r;

    while (wait(0) > 0)  // Lots of debugging opportunities here
        ;

    printf("%i\n", runningTotal);
    return 0;
}
票数 3
EN

Stack Overflow用户

发布于 2015-10-05 04:14:43

给定此代码:(摘自已发布代码)

代码语言:javascript
复制
for (i = 0; i < 10; i++) {
    pid = fork();
    if (pid == 0){
        close(fd[0]);
        t = ChildProcess();
        write(fd[1], &t, sizeof(t));
        exit(0);
    }
    close(fd[1]);
    read(fd[0], &r, sizeof(r));
    runningTotal = runningTotal + r;
    wait(&status);
}

有一个顺序问题。

当父级在循环的第一次迭代期间关闭fd1时,该文件描述符不会为循环的下一次迭代“神奇地”打开。

循环中父级的代码需要检查从调用read()返回的值,以确保操作成功。(在通过循环的第一次迭代之后,它可能没有成功,因此变量'r‘将保持不变。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32940575

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档