【问题标题】:Not all of my child processes running the end of my for loop并非我的所有子进程都在我的 for 循环结束时运行
【发布时间】:2021-06-29 15:01:13
【问题描述】:

我有一个项目,我需要创建 N 个子进程并在它们之间进行选举。所以到目前为止,我已经制作了一个生成随机数的函数(对于选举,他们必须比较他们被赋予的数字,然后选出较低的数字)。然后,我坚持让它们与管道通信以比较数字。我的问题是只有我的第一个子进程运行这个 for 循环的结尾我真的不明白为什么。到目前为止,这是我的所有代码:

void comparerIdElection(int (*pipes)[2], int numProc)
{


for (int i = 0; i < NBPROC; ++i)
    {
    if (numProc!=i)
    {
        close(pipes[i][0]);
        printf("je suis %d et je ferme la pipe [%d][0]\n",getpid(),i );
    }else printf("je suis %d et je laisse la pipe [%d][0] \n",getpid(),i );
    if (numProc +1 != i)
    {
        close(pipes[i][1]);
        printf("je suis %d et je ferme la pipe [%d][1]\n",getpid(),i );
    }else printf("je suis %d et je laisse la pipe [%d][1] \n",getpid(),i );
}


//Generate a random number for my child process
int GenererIdElection ()
{
    srand(time(NULL)^getpid()<<16);
    return rand()%NBPROC;
}






   int main(int argc, char const *argv[])
{
    int N = NBPROC, idElection, numProc= -1; 
    int pere = getpid();
/*Creation du nombre de pipe adequat */
    int pipes[N][2];
    int pids[N];
/* Indique l'etat du processus C = Candidat, B =B battu , E = Elu*/
    char etat ; 
    printf("le nombre de processus que je crée est : %d\n", N);


// Creation d'un nombre de N processus fils par le même pere
    for (int i = 0; i < N; ++i)
    {
            if(getpid()==pere){
                fork() ; 
                numProc ++ ;
            }       
    }

    if (getpid() != pere)
    {
        pids[numProc] = getpid();
        etat = 'C';
        while(etat == 67)
        {
            idElection = GenererIdElection();
            printf("je suis %d et j'ai eu %d, mon num proc est %d \n",getpid(), idElection, numProc);
            comparerIdElection(pipes, numProc);
            printf("hop\n");
            etat ='B';
            
        }

    }


    if (getpid()==pere)
    {
    /*On attend la fin de chaque processus
     pour mettre un terme au processu pere*/
        for (int i = 0; i < N; ++i)
        {
            wait(&pids[i]);
        }
    }
    exit(0);
}

这是执行后会发生的情况(我翻译了所有 printf):

[终端][1]

编辑:由于缺乏声誉,我无法发布图片,因此我复制/粘贴:

我是 1854,我得到 1,我的 numproc 是:0
我是 1854 我不关闭管道 [0][0]
我是 1854 我关闭 [0][1]
我是 1854 我关闭管道 [1][0]
我是 1854 我不关闭管道 [1][1]
我是 1854 我关闭管道 [2][0]
我是 1854 我关闭 [2][1]

我是 1855,我得到 1,我的 numproc 是:1
我是 1855 我关闭管道 [0][0]
我是 1855 我关闭 [0][1]
我是 1855 我不关闭管道 [1][0]
我是 1856,我得到了 1,我的 numproc 是:2
我是 1856 我关闭管道 [0][0]
我是 1856 我关闭 [0][1]
我是 1856 我关闭管道 [1][0]

NB : NBPROC = 3 在这种情况下,但无论数值如何,除了第一个子进程之外它都不起作用。

【问题讨论】:

  • 管道 fd 设置在哪里,否则大多数 close() 只是返回 -EBADF
  • 哦,该死的,你说得对,这是一个荒谬的错误,但我想知道为什么它对第一个进程子进程有效,当 i=0 时,如果你对此有所了解:我是拿它。谢谢你的回答!
  • 我的解释对你的情况有用吗? fds 之一总是设置为 1 是实际原因吗?

标签: c pipe fork


【解决方案1】:

我似乎对您的程序的行为有一个合理的解释。正如我已经在 cmets 中指出的那样,程序中存在一个明显的缺陷,即未设置 int pipes[N][2];,这最终会出现在 close() API 中,实际上只是导致 EBADF 被返回并且可能没有达到预期的效果。

至于程序的行为,可以通过检查数组int pipes[N][2]; 中填充的实际值来解释。由于原始问题中没有明确设置这些值,因此这些值基本上是未定义的,但是......

让我们尝试使用以下方法将它们设置为更合理的值:

int pipeVal = INT32_MIN;
if(argc == 2) {
    pipeVal = atoi(argv[1]);
}
for(int i = 0; i < N; ++i) {
    if(pipeVal != INT32_MIN) {
        pipes[i][0] =  pipes[i][1] = pipeVal;
    }
    printf("%d: Pipe pair %d-%d\n",getpid(), pipes[i][0], pipes[i][1]);
}

传入 0 产生输出:

61962: Number of process is : 3
61962: Pipe pair 0-0
61962: Pipe pair 0-0
61962: Pipe pair 0-0
61963: Election Id 0, numProc 0 
61963: Exiting while-loop
61964: Election Id 0, numProc 1 
61964: Exiting while-loop
61965: Election Id 0, numProc 2 
61965: Exiting while-loop

这似乎与预期一致:fork 3 个进程最终会退出。让我们尝试使用 1 的值

62033: Number of process is : 3
62033: Pipe pair 1-1
62033: Pipe pair 1-1
62033: Pipe pair 1-1
62034: Election Id 0, numProc 0 
62035: Election Id 2, numProc 1 
62036: Election Id 0, numProc 2 

现在这似乎很奇怪,因为没有进程真正退出while循环,但主程序成功终止。为了实际检查子程序的退出状态,我添加了以下代码:

if (getpid()==pere)
{
/*On attend la fin de chaque processus
 pour mettre un terme au processu pere*/
    for (int i = 0; i < N; ++i)
    {
        errno = 0;
        int stat_val;
        wait(&stat_val);
        #if DBG == 1
        printf("%d: WIFEXITED(%d),WEXITSTATUS(%d),WIFSIGNALED(%d),WTERMSIG(%d),WIFSTOPPED(%d),WSTOPSIG(%d),WIFCONTINUED(%d)\n", getpid(), WIFEXITED(stat_val),WEXITSTATUS(stat_val),WIFSIGNALED(stat_val),WTERMSIG(stat_val),WIFSTOPPED(stat_val),WSTOPSIG(stat_val),WIFCONTINUED(stat_val));
        #endif
    }
}

这是传入 1 作为参数的输出:

62215: WIFEXITED(1),WEXITSTATUS(0),WIFSIGNALED(0),WTERMSIG(0),WIFSTOPPED(0),WSTOPSIG(0),WIFCONTINUED(0)
62215: WIFEXITED(1),WEXITSTATUS(0),WIFSIGNALED(0),WTERMSIG(0),WIFSTOPPED(0),WSTOPSIG(0),WIFCONTINUED(0)
62215: WIFEXITED(1),WEXITSTATUS(0),WIFSIGNALED(0),WTERMSIG(0),WIFSTOPPED(0),WSTOPSIG(0),WIFCONTINUED(0)

这个输出表明所有进程正常退出,没有被任何信号异常停止。

线索在这些进程试图关闭的实际fds 中。在 Linux 中(至少)一个进程一旦创建就有 3 个文件描述符:0 对应于stdin1 对应于stdout2 对应于stderr。当 0 作为参数传递给程序时,进程最终会关闭 stdin (close(0)) 无论如何都没有使用,因此没有问题,它们随后退出 comparerIdElection() 和 while 循环。当 1 作为参数传递给程序时,进程最终会关闭 stdout (close(1)),因此应该在控制台上看不到任何应该写入输出的内容,但它们仍然 退出comparerIdElection() 和随后的while 循环,从而退出每个进程的WIFEXITED(1)

现在来看实际共享的程序,未指定最终填充的实际值是什么,但如果数组中的 N*2 fds 之一设置为 1,则行为如上 (传入 1) 将被展示,即即使printfs 不会被写入控制台,进程确实会退出 while 循环,并且主父进程能够成功地等待进程。在我的电脑上(我也怀疑在你的电脑上),这些数组元素中的至少一个的实际值始终设置为 1。

我的 Mac 上管道 fd 对的值:

61120: Pipe pair -296602944-32766
61120: Pipe pair 23978080-1
61120: Pipe pair 64-0

他们在TryItOnline上的价值观:

25090: Pipe pair 0-0
25090: Pipe pair 68079952-32708
25090: Pipe pair 1-0

它们在OnlineGDB上的值(需要添加编译器标志-DNBPROC=3):

5612: Pipe pair 1505064448-32611                                                                                                                                         
5612: Pipe pair 1507242440-32611                                                                                                                                         
5612: Pipe pair 1-0

无论NBPROC 的值如何,该分析都应该成立,因为直到管道fds 中有1,该进程最终将关闭它自己的stdout 并表现出类似的行为。

这是一个完整的程序,其中包含一些可以通过传入 DBG=1 和一些 PID 标记来确定日志来自哪个进程的工具:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <sys/wait.h>
#include <errno.h>
#include <string.h>
#include <stdint.h>

void comparerIdElection(int (*pipes)[2], int numProc)
{
    for (int i = 0; i < NBPROC; ++i)
    {
        if (numProc!=i)
        {
            #if DBG == 1
            printf("%d: Before close  pipe [%d][0](%d)\n",getpid(),i , pipes[i][0]);
            #endif
            errno = 0;
            close(pipes[i][0]);
            #if DBG
            printf("%d: closed  pipe [%d][0](%d) %s\n",getpid(),i, pipes[i][0], strerror(errno));
            #endif
        } else  {
            #if DBG == 1
            printf("%d: no action on pipe [%d][0](%d) \n",getpid(),i, pipes[i][0] );
            #endif
        }
        if (numProc +1 != i)
        {
            #if DBG == 1
            printf("%d: Before close  pipe [%d][1](%d)\n",getpid(),i, pipes[i][1] );
            #endif
            errno = 0;
            close(pipes[i][1]);
            #if DBG == 1
            printf("%d: close pipe [%d][1](%d) %s\n",getpid(),i, pipes[i][1], strerror(errno) );
            #endif
        } else {
            #if DBG == 1
            printf("%d: no action pipe [%d][1](%d) \n",getpid(),i, pipes[i][1] );
            #endif
        }
    }
}

//Generate a random number for my child process
int GenererIdElection ()
{
    srand(time(NULL)^getpid()<<16);
    return rand()%NBPROC;
}

int main(int argc, char const *argv[])
{
    int N = NBPROC, idElection, numProc= -1; 
    int pere = getpid();
    int pipes[N][2];
    int pids[N];
    char etat ;
    printf("%d: Number of process is : %d\n", getpid(), N);
    int pipeVal = INT32_MIN;
    if(argc == 2) {
        pipeVal = atoi(argv[1]);
    }
    for(int i = 0; i < N; ++i) {
        if(pipeVal != INT32_MIN) {
            pipes[i][0] =  pipes[i][1] = pipeVal;
        }
        printf("%d: Pipe pair %d-%d\n",getpid(), pipes[i][0], pipes[i][1]);
    }

    for (int i = 0; i < N; ++i)
    {
        if(getpid()==pere){
            pid_t pid = fork() ;
            numProc++;
            if(pid == 0) {
                // sleep(10);
                #if DBG == 1
                printf("%d: After fork in the child got fork-pid %d\n", getpid(), pid);
                #endif
            } else {
                pids[numProc] = pid;
                #if DBG == 1
                printf("%d: After fork in the parent got fork-pid %d numProc %d pids[%d] = %d\n",
                    getpid(), pid, numProc, numProc, pids[numProc]);
                #endif
            }
        }
    }

    if (getpid() != pere)
    {
        etat = 'C';
        while(etat == 67)
        {
            idElection = GenererIdElection();
            printf("%d: Election Id %d, numProc %d \n",getpid(), idElection, numProc);
            comparerIdElection(pipes, numProc);
            etat ='B';
        }
        printf("%d: Exiting while-loop\n", getpid());
    }

    if (getpid()==pere)
    {
    /*On attend la fin de chaque processus
     pour mettre un terme au processu pere*/
        for (int i = 0; i < N; ++i)
        {
            errno = 0;
            int stat_val;
            wait(&stat_val);
            #if DBG == 1
            printf("%d: WIFEXITED(%d),WEXITSTATUS(%d),WIFSIGNALED(%d),WTERMSIG(%d),WIFSTOPPED(%d),WSTOPSIG(%d),WIFCONTINUED(%d)\n", getpid(), WIFEXITED(stat_val),WEXITSTATUS(stat_val),WIFSIGNALED(stat_val),WTERMSIG(stat_val),WIFSTOPPED(stat_val),WSTOPSIG(stat_val),WIFCONTINUED(stat_val));
            #endif
        }
    }
    printf("%d: Exiting process\n", getpid());
    exit(EXIT_SUCCESS);
}

【讨论】:

    猜你喜欢
    • 2015-11-26
    • 2020-11-08
    • 2021-06-21
    • 1970-01-01
    • 1970-01-01
    • 2016-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多