首页 > 解决方案 > 如何使用管道或任何其他方法将数据从多个子进程发送到父数组?

问题描述

我正在尝试通过创建多个进程fork()并对子进程进行一些数学运算,例如数组元素的总和,然后将值返回给父进程,父进程会将每个值保存parentArray在代码中。现在我的问题是如何在这个阶段做到这一点,我只收到第一个进程的一个值,其余值为零。是否有另一种传递价值的方式,或者可以通过管道完成?请帮我

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

void showReturnStatus(pid_t childpid,int status){
    if (WIFEXITED(status) && !WEXITSTATUS(status))
        printf("Child %ld terminated normally\n", (long)childpid);
    else if (WIFEXITED(status))
        printf("Child %ld terminated with return status %d\n",(long)childpid, WEXITSTATUS(status));
    else if (WIFSIGNALED(status))
        printf("Child %ld terminated due to uncaught signal %d\n",(long)childpid, WTERMSIG(status));
    else if (WIFSTOPPED(status))
        printf("Child %ld stopped due to signal %d\n",(long)childpid, WSTOPSIG(status));
}

int main(int argc, char *argv[])
{
    srand(time(0));
    int arraySize=9,noProcess=3,array[arraySize],status=0;
    pid_t pid;
    int parentSum=0;
    int parentArray[3],fd[2];     //fd file descriptor

    if(pipe(fd)==-1)
        return 0;

    for(int i=0 ;i<arraySize;i++)
        array[i]=(rand()%100)+1;
    
    for(int i=0;i<arraySize;i++){
        printf("\n %d : %d  ",i,array[i]);
    }
    printf("\nParent PID[%d] \n",getpid());
    
    for(int childP=0;childP<noProcess;childP++){
        int child=fork();
        int childSum;
        if(child==0){
            close(fd[0]);
            childSum=0.0;
            for(int i=childP*3;i<(childP+1)*3;i++)
                childSum+=array[i];
            printf("\nChild Process No [%d] PID [%d] Return Sum : %d \n",childP,getpid(),childSum);
            write(fd[1],&childSum,sizeof(childSum));
            close(fd[1]);
            exit(0); 
        }
        pid=wait(&status);
        showReturnStatus(pid,status);
        close(fd[1]);
        read(fd[0],parentArray,sizeof(parentArray));
        close(fd[0]);

    }
    for (int i=0;i<3;i++)
    {
        printf("\nValue Array : %d\n",parentArray[i]);
    }
    

    printf("\nParent Process with PID [%d] calculate Sum : %d\n",getppid());
    return 0;
}

标签: clinuxsystems-programming

解决方案


这是您的代码的修订版本,其中包含多项更改。

  • 它允许子进程同时运行。

  • 它关注各种错误情况。

  • 它每行打印 10 个数据条目。

  • 它检查数组大小是进程数的整数倍。

  • 它不会在父节点中过早关闭管道。

  • 它将错误报告给标准错误,并以失败状态退出。

  • 它在输出消息的末尾打印换行符;它不需要在消息的开头打印换行符。

  • 我宁愿避免noProcess,因为它暗示“没有过程”;我重命名了它numProcess

  • 该代码使用numProcessandarraySize来控制所有相关的循环等。

  • 它在父进程中计算并打印总和,以便可以快速检查来自子进程的值。这也表明,出于本练习的目的,使用流程是一种人工制品。

  • 它打印每行具有多个条目的数组。

  • 我调整了计算以生成数字 1..99,以便格式%2d统一工作。

  • 我使用这些选项(源代码pipe79.c、程序pipe79)进行编译:

    gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes pipe79.c -o pipe79
    
  • 测试argc > 0只是为了确保它argc被使用——如果不是,代码由于未使用的变量而无法编译。

  • 我介绍了变量numPerProcessstart并且stop因为这些值至少被使用了两次。

  • 除了将其设置为静态之外,我不需要进行showReturnStatus()任何修改,这又是必要的,因为我使用了编译选项。static该函数不在此源文件之外使用,因此 IMO无论如何都应该使用它。如果它在其他地方使用,它将在一个标题中声明,该标题将包含在定义它的位置和使用它的位置。

  • 可能还有其他可以指出的详细更改,但我忘记了我进行了更改。

代码:

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

static void showReturnStatus(pid_t childpid, int status)
{
    if (WIFEXITED(status) && !WEXITSTATUS(status))
        printf("Child %ld terminated normally\n", (long)childpid);
    else if (WIFEXITED(status))
        printf("Child %ld terminated with return status %d\n", (long)childpid, WEXITSTATUS(status));
    else if (WIFSIGNALED(status))
        printf("Child %ld terminated due to uncaught signal %d\n", (long)childpid, WTERMSIG(status));
    else if (WIFSTOPPED(status))
        printf("Child %ld stopped due to signal %d\n", (long)childpid, WSTOPSIG(status));
}

int main(int argc, char *argv[])
{
    srand(time(0));
    int arraySize = 72;
    int numProcess = 6;
    int array[arraySize];
    int fd[2];
    const char *arg0 = (argc == 0) ? "pipe79" : argv[0];    /* Use argc */

    assert(arraySize % numProcess == 0);
    int numPerProcess = arraySize / numProcess;

    if (pipe(fd) == -1)
    {
        fprintf(stderr, "%s: failed to create a pipe\n", arg0);
        exit(EXIT_FAILURE);
    }

    int sum = 0;
    for (int i = 0; i < arraySize; i++)
    {
        array[i] = (rand() % 99) + 1;
        sum += array[i];
    }

    int width = 0;
    const char *pad = "";
    for (int i = 0; i < arraySize; i++)
    {
        width += printf("%s%2d: %2d", pad, i, array[i]);
        pad = ", ";
        if (width > 72)
        {
            putchar('\n');
            width = 0;
            pad = "";
        }
    }
    if (width > 0)
        putchar('\n');
    printf("Sum calculated by parent: %d\n", sum);
    printf("Parent PID[%d]\n", getpid());

    for (int childP = 0; childP < numProcess; childP++)
    {
        int child = fork();
        if (child < 0)
        {
            fprintf(stderr, "%s: failed to fork child %d\n", arg0, childP + 1);
            exit(EXIT_FAILURE);
        }
        if (child == 0)
        {
            close(fd[0]);
            int childSum = 0;
            int start = childP * numPerProcess;
            int stop = start + numPerProcess;
            printf("Child PID %d: processing rows %d..%d\n", getpid(), start, stop - 1);
            for (int i = start; i < stop; i++)
                childSum += array[i];
            printf("Child Process No [%d] PID [%d] Return Sum : %d\n", childP, getpid(), childSum);
            if (write(fd[1], &childSum, sizeof(childSum)) != sizeof(childSum))
            {
                fprintf(stderr, "Child Process No [%d] PID [%d] failed to write to the pipe\n",
                        childP, getpid());
                exit(EXIT_FAILURE);
            }
            close(fd[1]);
            exit(0);
        }
    }

    close(fd[1]);

    sum = 0;
    pid_t pid;
    int status = 0;
    while ((pid = wait(&status)) != -1)
    {
        int number;
        showReturnStatus(pid, status);
        if (read(fd[0], &number, sizeof(number)) != sizeof(number))
        {
            fprintf(stderr, "%s: parent process got a short read on the pipe\n", arg0);
            exit(EXIT_FAILURE);
        }
        printf("sum from pipe: %d\n", number);
        sum += number;
    }

    printf("Parent Process with PID [%d] accumulated sum : %d\n", getpid(), sum);
    return 0;
}

样本输出:

 0: 68,  1: 13,  2: 74,  3: 37,  4: 88,  5:  4,  6: 73,  7: 94,  8:  2,  9: 71
10: 20, 11: 19, 12: 93, 13: 96, 14: 13, 15: 96, 16: 98, 17: 12, 18: 94, 19: 10
20: 27, 21: 38, 22: 48, 23: 14, 24: 18, 25: 50, 26: 61, 27: 15, 28: 88, 29: 41
30:  2, 31: 99, 32: 42, 33:  8, 34: 55, 35: 32, 36: 29, 37: 53, 38: 78, 39: 15
40: 69, 41: 19, 42: 85, 43: 78, 44:  3, 45: 59, 46: 96, 47: 37, 48: 35, 49: 95
50: 59, 51: 12, 52: 63, 53: 34, 54: 31, 55: 17, 56: 88, 57: 63, 58: 74, 59: 15
60: 10, 61: 38, 62: 24, 63: 27, 64: 70, 65: 64, 66: 40, 67: 43, 68: 87, 69: 82
70: 35, 71: 11
Sum calculated by parent: 3451
Parent PID[58056]
Child PID 58057: processing rows 0..11
Child Process No [0] PID [58057] Return Sum : 563
Child PID 58058: processing rows 12..23
Child Process No [1] PID [58058] Return Sum : 639
Child PID 58059: processing rows 24..35
Child Process No [2] PID [58059] Return Sum : 511
Child PID 58060: processing rows 36..47
Child Process No [3] PID [58060] Return Sum : 621
Child PID 58061: processing rows 48..59
Child Process No [4] PID [58061] Return Sum : 586
Child 58059 terminated normally
sum from pipe: 563
Child 58060 terminated normally
sum from pipe: 639
Child 58058 terminated normally
sum from pipe: 511
Child 58057 terminated normally
sum from pipe: 621
Child 58061 terminated normally
sum from pipe: 586
Child PID 58062: processing rows 60..71
Child Process No [5] PID [58062] Return Sum : 531
Child 58062 terminated normally
sum from pipe: 531
Parent Process with PID [58056] accumulated sum : 3451

推荐阅读