等待父进程信号,使子进程处于等待状态

4
我想从一个父进程创建N个子进程。我希望所有的子进程在同一时间开始执行(一个测量时间的函数)。因此,我将这个函数放在信号处理程序中,当父进程完成创建(fork)所有子进程后,它向所有子进程发送信号(使用kill(children_id))以让它们开始执行。以下是代码,但它没有按预期工作。具体而言,它分叉了所有子进程,但根本没有执行“measure_time”函数。该函数仅记录执行时间并打印出来。 请问是否有哪里做错了?
    int n_task = 4;
    for (i = 0; i < n_task; i++){
            pid = fork();
            if (pid < 0){
                    printf("cannot fork!\n");
            } else
            if (pid == 0){ //child
                    printf("printed from child [%d]\n", getpid());                        
                    signal(SIGUSR1, measure_time); //measure_time is a function
                    exit(0);
            } else {
                    pid_array[i] = pid;
            }
    }

    //This code is executed from parent only
    for (int i = 0; i < n_task; i++)
    {
            kill(pid_array[i], SIGUSR1);                
    }

你使用fork()而不是pthread有任何原因吗? - i_am_jorf
@jeffamaphone:这是一个需要使用fork()signal()sigaction()kill()的练习吗?可能足够的理由了。 - Jonathan Leffler
是的,我只是想尝试使用fork()。 - Zk1001
2个回答

8
if (pid == 0){ //child
    printf("printed from child [%d]\n", getpid());                        
    signal(SIGUSR1, measure_time); //measure_time is a function
    exit(0);
}

孩子们被创建并设置了处理程序,但立即退出(即死亡)。让它们睡眠或阻塞在某些东西上,以便父进程有足够的时间传递信号。 更新
#define _POSIX_SOURCE

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

void measure_time(int sig)
{
    printf("child [%d] received signal %d\n", getpid(), sig);
}

int main(int argc, char *argv[])
{
    int n_task = 4;

    pid_t pid;
    pid_t pid_array[n_task];

    for (int i = 0; i < n_task; i++)
    {
        pid = fork();

        if (pid < 0)
        {
            perror("fork");
            exit(1);
        }

        if (pid == 0) //child
        {
            printf("printed from child [%d]\n", getpid());
            signal(SIGUSR1, measure_time); //measure_time is a function
            sleep(5);

            exit(0);
        }

        //parent
         pid_array[i] = pid;
    }    

    //This code is executed from parent only
    sleep(1);

    for (int i = 0; i < n_task; i++)
        kill(pid_array[i], SIGUSR1);

    for (int i = 0; i < n_task; i++)
        wait(NULL);    

    return (0);
}

所有进程和线程都受操作系统调度程序的支配。在你的初始代码中,子进程和父进程都有可能在你希望发生的事件序列之前终止。子进程在父进程发送信号之前可能会死亡;父进程可能在子进程设置其处理程序之前发送其信号(并且 SIGUSR1 会杀死该进程,因为在没有处理程序的情况下这是其默认值)。由于要执行的代码很少,所有这些事件都在毫秒级时间内完成,比任何这些进程被调度以运行(因此设置足够的内容以满足你的期望)的时间还短。我添加了一些 sleep 以便给它们留出一些缓冲区,并添加了一个 wait 以便父进程不会死亡。这应该可以让你看到它是如何工作的。


pause() 函数是等待信号到达的经典和最简单的方法。它永远不会正常返回;只有在信号中断它时才会返回。 - Jonathan Leffler
尝试了你的代码,但是它不能让所有4个任务同时开始。更具体地说,我在measure_time()中添加了sleep(1)。子进程们每隔1秒打印一次他们的“接收信号”。你能再试一次吗? - Zk1001
我将父进程的kill/wait代码编辑成了两个循环。也许这就是你看到的问题。非常抱歉之前对你有些冷淡,毕竟我早上连咖啡都还没喝完。 - Duck

2
if (pid == 0){ //child
    printf("printed from child [%d]\n", getpid());                        
    signal(SIGUSR1, measure_time); //measure_time is a function
    pause();
    exit(0);
}

我认为问题在于,子进程创建后立即被终止了。因此,使用pause()函数等待信号的到来。

如果一些子进程无法按预期响应,请尝试这样做。

for (j = 0; j < n_task; j++)
    {
            kill(pid_array[j], SIGUSR1); 
            sleep(1);
    }

这与Duck的答案有些相似,所以我在这里发表评论。我尝试过这个方法,但是在创建了4个线程中,只有1个(有时候是2个)线程被执行。还有什么遗漏的吗? - Zk1001
for (j = 0; j < n_task; j++) { kill(pid_array[j], SIGUSR1); sleep(1); }尝试这种方式,它会起作用。(我不确定为什么会发生这种情况,但我认为是因为父进程在某些子进程安装信号处理程序之前发送了信号。) - Deadlock
但这并不能帮助您实现您的目的,即从所有子进程同时启动(一个函数-测量时间)。但是所有子进程都将被执行。 - Deadlock
是的,它按照你想的那样工作。太好了。但是,我必须延迟信号发送!这不是我想要的。我想发送信号,更准确地说,广播给所有子节点,并让它们同时开始,或多或少。有人能给个提示吗? - Zk1001
你们是认真的吗?“有点相似”? - Duck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接