LINUX IPC:使用PIPE将不同的值传递给CHILD进程,除了第一次,在C中

时间:2017-09-27 22:02:33

标签: c linux ipc

我有一组taskid分组到几个组,每个组由唯一的groupid标识。

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

  2. 每个孩子都有权专门为其所关联的GROUP提供服务。因此,我希望在产生后立即将唯一groupId传递给每个子流程,以便它只执行与其groupId相关联的任务。

  3. 父母只有父母的groupId写作,在CHILD产生时也只有一次。孩子不应该向父母写回任何东西。 (单向沟通 - PARENT - write/CHILD -read

  4. 经过一番研究,我写了一个如下伪代码。 (这是一个可编辑的代码)。

    #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.1] 0~1000    1~1002  2~1004  3~1006
        [1.1] writing to child: 15068 parent 15067 i 0 groupId 1000
        [2.1] Processing 0 th Process pid: 15068 groupId 1000 sleep 3 sec
        [1.1] writing to child: 15069 parent 15067 i 1 groupId 1002
        [2.1] Processing 1 th Process pid: 15069 groupId 0 sleep 3 sec
        [1.1] writing to child: 15070 parent 15067 i 2 groupId 1004
        [2.1] Processing 2 th Process pid: 15070 groupId 0 sleep 3 sec
        [1.1] writing to child: 15071 parent 15067 i 3 groupId 1006
        [1.2] waiting for pid: 15068
        [2.1] Processing 3 th Process pid: 15071 groupId 0 sleep 3 sec
    
        // This Gap is not a part of output. It indicates the sleep worked from here.
    
        [2.2] Returning from sleep 0 Process pid: 15068 groupId 1000 sleep 3 sec
        [0.2] Did we Finished total 5 PID 15068
        [2.2] Returning from sleep 1 Process pid: 15069 groupId 0 sleep 3 sec
        [0.2] Did we Finished total 5 PID 15069
        [1.3] Finished pid: 15068
        [1.2] waiting for pid: 15069
        [1.3] Finished pid: 15069
        [1.2] waiting for pid: 15070
        [2.2] Returning from sleep 2 Process pid: 15070 groupId 0 sleep 3 sec
        [0.2] Did we Finished total 5 PID 15070
        [1.3] Finished pid: 15070
        [1.2] waiting for pid: 15071
        [2.2] Returning from sleep 3 Process pid: 15071 groupId 0 sleep 3 sec
        [0.2] Did we Finished total 5 PID 15071
    

    输出中的编号系统如下所示。

        [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)
    

    我在使用此代码时遇到的问题很少。

    1。随机数 我依靠随机数来为CHILD产生不均匀的睡眠时间,这模仿了实际情况。即使我在srand(time(NULL))函数中放置了main函数,但rand()中的process() function始终生成相同的输出(3 seconds在上面的输出中)。是因为CPU如此之快?如果是,是否有更好的种子?

    2。阅读PIPE
    除非第一次,从CHILD过程读取的groupId总是变为零。如下面的输出所示。

    [2.1] Processing 2 th Process pid: 15070 groupId 0 sleep 3 sec

    您可以在父母write时清楚地看到,groupId被正确选中。 (如下所示):

    [1.1] writing to child: 15070 parent 15067 i 2 groupId 1004

    如何改进此代码以实现结果。或者这个逻辑是否有任何缺陷(我问这个是因为我是IPC的初学者,没有太多的经验)。我是否需要为critical section数组实现groupId

    提前致谢。

1 个答案:

答案 0 :(得分:1)

随机数。您在分叉之前调用srand,因此所有子项都会继承相同的种子,因此他们对rand的调用将产生相同的数字。您可以在循环内增加种子,让每个孩子自己调用srand

通讯。父母在产生第一个孩子后关闭parent_to_child[0],因此以后的孩子会继承一个已关闭的管道,并且无法通过它接收groupID信息。只有完成所有分叉后,父母才能关闭该管道。