LinuxIPC:使用管道向子进程传递不同的值不起作用,C中第一次除外

LinuxIPC:使用管道向子进程传递不同的值不起作用,C中第一次除外,c,linux,ipc,C,Linux,Ipc,我有一组TaskID,分为几个组,每个组由一个唯一的groupid标识 对于每个组,我需要生成一个子进程,每个子进程都充当服务器——这意味着它们从其他进程获取消息,并在处理后返回结果 每个儿童都有权专门为与其相关的群体服务。因此,我希望在生成后立即将唯一的groupId传递给每个子进程,以便它只执行与其groupId相关联的任务 只有父对象向子对象写入groupId,在子对象生成时也只有一次。孩子不应该给父母写任何东西。单向通信-父级-写入/子级-读取 经过一点研究,我编写了一个伪代码,如下所示

我有一组TaskID,分为几个组,每个组由一个唯一的groupid标识

对于每个组,我需要生成一个子进程,每个子进程都充当服务器——这意味着它们从其他进程获取消息,并在处理后返回结果

每个儿童都有权专门为与其相关的群体服务。因此,我希望在生成后立即将唯一的groupId传递给每个子进程,以便它只执行与其groupId相关联的任务

只有父对象向子对象写入groupId,在子对象生成时也只有一次。孩子不应该给父母写任何东西。单向通信-父级-写入/子级-读取

经过一点研究,我编写了一个伪代码,如下所示。这是一个可编译的代码

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

int process(int n);

#define NGROUPID 5
#define INIT_GROUPID 1000

int parent_to_child[2];
int main()
{
    pid_t pid;
    pid_t pid_array[NGROUPID];  //Child pid array.
    int groupId[NGROUPID];
    int groupID = 0,i;

    srand((unsigned int) time(NULL));  //random seed
    groupId[0] = INIT_GROUPID;

    printf("[0.1] ");
    //set groupIds 
    for(i=1; i < (NGROUPID - 1); i++)
    {
        int j = i -1;
        groupId[i]= groupId[j] + 2;
        printf("%d~%d\t",j,groupId[j]);

    }
    printf("%d~%d\n",i-1,groupId[i-1]);

    fflush(stdout); //Flushing stdout before pipe call
    pipe(parent_to_child);

    // For each groupId, spawn child process 
    for (i = 0; i < (NGROUPID - 1); i++ )
    {

        pid = fork();
        if(pid < 0)
        {
            perror("fork failed\n");
            exit(1);
        }
        if(pid == 0)
        {
            process(i); //Child Process.
            break;  //Is it necessory to break? Will it create Children of children?
        }
        if(pid > 0)
        {
            close(parent_to_child[0]); //parent is not reading from child
            printf("[1.1] writing to child: %d parent %d i %d groupId %d\n",pid,getpid(),i,groupId[i]);
            write(parent_to_child[1], &groupId[i], sizeof(int)); //Passing groupId to Child.
            pid_array[i] = pid;  //To shutdown cleanly.
        }
    }
    if(pid > 0)
    {

        for (i = 0; i < (NGROUPID - 1); i++ )
        {
            printf("[1.2] waiting for pid: %d\n",pid_array[i]);
            waitpid(pid_array[i], NULL, 0);
            printf("[1.3] Finished pid: %d\n",pid_array[i]);
        }

    }

    printf("[0.2] Did we Finished total %d PID %d\n", NGROUPID, getpid());
    if(pid > 0)
        printf("[1.4] There are no zombies\n");

    return 0;

}

//This is a pseudo code. Actual code will consists of receiving messages
// from other processes (using message queue) and return the results after processing.
// This act like a SERVER process, which will not quit in usual scenario. 
int process(int n)
{
    int groupID = 0;
    close(parent_to_child[1]); //we are not going to return to Parent.
    read(parent_to_child[0], &groupID, sizeof(int)); //Read from Parent
    unsigned int sec = (rand() % 10) + 1;
    printf("[2.1] Processing %d th Process pid: %d groupId %d sleep %d sec\n",n, getpid(), groupID, sec);
    sleep(sec);
    printf("[2.2] Returning from sleep %d Process pid: %d groupId %d sleep %d sec\n",n, getpid(), groupID, sec);
}
输出中的编号系统如下所示

    [0.*] - Indicate that Print from General part of code (neither parent or child)
    [1.*] - Indicate that Print from PARENT process. (pid > 0)
    [2.*] - Indicate that Print from CHILD process.  (pid == 0)
对于这段代码,我面临的问题很少

一,。随机数 我依靠随机数来产生孩子们不均衡的睡眠时间,这与实际情况类似。尽管我已经在主函数中添加了srandtimeNULL函数,但是进程函数中的rand总是在上面的输出中生成相同的输出3秒。是不是因为CPU太快了??。如果有,有更好的种子吗

二,。阅读管 除非是第一次,否则从子进程读取的groupID始终为零。如以下输出所示

[2.1]处理第二个进程pid:15070 groupId 0睡眠3秒

您可以清楚地看到,在父级写入时,正确地拾取了groupId。如下所示:

[1.1]写信给孩子:15070家长15067 i 2组ID 1004

如何改进此代码以获得结果。或者在这个逻辑中有什么缺陷吗?我问这个问题是因为我是IPC的初学者,之前没有太多经验。我是否需要为groupId阵列实现一个关键部分

提前感谢。

随机数。在fork之前调用srand,因此所有子级都继承相同的种子,因此它们对rand的调用将生成相同的数字。您可以在循环内增加种子数,并让每个子项单独调用srand


沟通。父级在生成第一个子级后关闭父级到子级[0],因此以后的子级将继承一个关闭的管道,并且无法通过它接收groupID信息。只有在所有分叉完成后,家长方可关闭该管道。

您的错误检查在哪里?管道、写入、读取、等待PID等都可能失败。读/写可以读/写的数据比请求的少。也许你应该检查更多库调用的返回值,看看它们是否成功。注意rand是一个伪随机数生成器PRNG:它实际上是确定性的,而不是真正的随机数,因此当给定相同的种子并调用相同的次数后,它总是给出相同的结果。而分叉进程肯定会从相同的状态开始。您可以在子进程中使用srandtimeNULL+getpid之类的东西来为每个进程获取不同的种子。此行:pipeparent\u to\u child;仅创建一个管道。家长“盲目”地向那条管道写信。任何人都可以猜测哪个子进程将访问/读取该管道。建议为每个子级生成单独的管道。注意:此语句:closeparent_to_child[0];将在第一次迭代后失败。
    [0.*] - Indicate that Print from General part of code (neither parent or child)
    [1.*] - Indicate that Print from PARENT process. (pid > 0)
    [2.*] - Indicate that Print from CHILD process.  (pid == 0)