Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 在处理程序中阻止新信号_C_Linux_Multithreading_Signals - Fatal编程技术网

C 在处理程序中阻止新信号

C 在处理程序中阻止新信号,c,linux,multithreading,signals,C,Linux,Multithreading,Signals,我有一个管理子进程(fork、execve)的父进程。我在父级中创建了一个处理程序来捕获来自子级的SIGCHLD信号,以便调用waitpid(),并采取适当的操作,例如重新启动子级 我从sigaction()的手册页面了解到,在信号处理程序中,默认情况下,相同类型的其他信号将被阻止。我当然希望这种行为,所以我决定测试它 我在信号处理程序的末尾放了一个sleep(我自己的实现使用了clock\u nanosleep()在一个循环中,该循环在中断时恢复),并向孩子发送了一个SIGINT。这使它及时退

我有一个管理子进程(fork、execve)的父进程。我在父级中创建了一个处理程序来捕获来自子级的SIGCHLD信号,以便调用
waitpid()
,并采取适当的操作,例如重新启动子级

我从
sigaction()
的手册页面了解到,在信号处理程序中,默认情况下,相同类型的其他信号将被阻止。我当然希望这种行为,所以我决定测试它

我在信号处理程序的末尾放了一个sleep(我自己的实现使用了
clock\u nanosleep()
在一个循环中,该循环在中断时恢复),并向孩子发送了一个SIGINT。这使它及时退出并将SIGCHLD发送给家长。我把事实记录下来,开始睡10秒钟。现在,我给新孩子发送了另一个信号(sighandler第一次重新启动了它),并惊讶地看到另一个日志和睡眠发生了

这怎么可能?当我使用调试器连接到父线程时,它清楚地显示两个不同的线程在调用我的信号处理程序时被中断,它们现在都处于睡眠状态。如果这种情况持续下去,我的线程就会用完

我理解将长时间睡眠放入信号处理器是一件愚蠢的事情,但它确实说明了这一点;我希望在/proc/[PID]/status中看到第二个标记为挂起的信号,但是它被传递了

以下是我代码的相关部分:

设置SIGCHLD处理程序:

typedef struct SigActType {
    struct sigaction act;
    int              retval;
    void             (*func)(int);
}SigActType;
static SigActType sigActList[64];

public void setChildHandler(void (*func)(int)) {
    SigActType *sat = &sigActList[SIGCHLD];

    sat->act.sa_sigaction = sigchldHandler;
    sigemptyset(&sat->act.sa_mask);
    sigaddset (&sat->act.sa_mask, SIGTERM);
    sigaddset (&sat->act.sa_mask, SIGINT);
    sigaddset (&sat->act.sa_mask, SIGCHLD);
    sat->act.sa_flags = SA_SIGINFO;
    sat->retval = 0;
    sat->func = func;
    sigaction(SIGCHLD, &sat->act, NULL);
}

static void sigchldHandler(int sig, siginfo_t *si, void *thing) {
    SigActType *sat = &sigActList[SIGCHLD];

    if (sat->func) {
        sat->func(si->si_pid);
    }
}
使用这个:

int main(int argc, char **argv) {
    setChildHandler(manageChildSignals);
    ...
}

static void manageChildSignals(int d) {
    if ((pid = waitpid(-1, &stat, WAIT_MYPGRP)) > 0) {
        ... restart child if appropriate
    }
    printf("start of pause...\n");
    mySleep(10);
    printf("end of pause...\n");
}
Stdout清楚地表明:

(when I type kill -2 [PID]
start of pause
(when the new child is started and I type kill -2 [NEWPID]
start of pause
...10 seconds slide past...
end of pause
end of pause
我不明白为什么会发生这种情况。如您所见,我甚至在
sigaction()
的块掩码中添加了SIGCHLD,以鼓励它做正确的事情

欢迎指点

默认情况下,相同类型的信号将被阻止

是的,但仅针对从调用的线程

来自(粗体我强调):

sa_mask指定了应阻止的信号屏蔽(即。, 添加到包含信号处理程序的线程的信号掩码 在执行信号处理程序期间调用

由于信号处理是每个进程进行的,因此任何其他未阻塞相关信号的线程都可能接收到该信号,也就是说,被中断并对其进行处理

如果这种行为不是您想要的,您可能应该修改程序处理信号的方式的设计,按照默认方式,每个线程的所有信号都被阻塞,并且只有一个特定线程的信号接收未被阻塞

更新:

子线程从父线程继承信号掩码

如果信号处理仅由一个特定线程完成,则在创建任何其他线程之前,让主线程阻止所有信号。然后创建一个特定的线程来执行信号处理,并让该线程解锁要处理的信号。这个概念还允许像每个信号一个线程这样的模型

在多线程环境中,用于在每个线程基础上屏蔽信号


请注意,
sigprocmask()
在多线程进程中的行为是未指定的,请使用
pthread\u sigmask()

mysleep做什么?它是使用
clock\u nanosleep()实现的
sleep()
在一个循环中,当它返回EINTR时,它会休眠正确的时间,即使被中断。哦,你正在使用多个线程。抱歉;我应该说清楚的。是的,
main()
设置信号处理程序,然后工作线程进入睡眠状态。其他线程做这项工作。在这种情况下,每个线程都有资格被强制跳转到信号。“仅针对调用sigaction的线程”?这也许可以解释。我的其他线程可能会被中断来处理这个信号?只是不是我称之为sigaction的那个“主要”的?是的。但我认为处理信号的不同线程不会导致问题。我认为
sigaction()
适用于该流程!用于“更新”。是的,我想到了这一点,并在子进程启动时将它们放回原位。@jrichemont:is就是这样做的,处理是为进程的所有线程安装的。然而,对于实际接收到信号的线程,会进行Making。掩码是在每个线程的基础上完成的。请参阅我的答案中关于pthread_sigmask()的补充。