gpt4 book ai didi

c - C 信号处理程序中的竞争条件

转载 作者:行者123 更新时间:2023-12-02 00:25:15 32 4
gpt4 key购买 nike

我正在做一些类(class),我们收到了以下代码。有些问题询问不同行代码的作用,这很好,我理解,但问题是“这个程序包含竞争条件。它在哪里以及为什么出现?”

代码:

#include <stdio.h>
#include <signal.h>

static void handler(int signo) {
printf("This is the SIGUSR1 signal handler!\n");
}

int main(void) {
sigset_t set;
sigemptyset(&set);
sigset(SIGUSR1, handler);
sigprocmask(SIG_SETMASK, &set, NULL);

while(1) {
printf("This is main()!\n");
}
return 0;

}

我在想,竞争条件是,当信号到达时,无法知道“This is main”或“This is the SIGUSR1”将打印什么顺序,但如果有人可以确认或澄清这一点我非常感激。他还询问如何修复它(竞争条件),而不是寻找完整的答案,但任何提示将不胜感激。

最佳答案

确实不存在竞争条件;比那更糟糕。根据 POSIX 标准,程序的行为是未定义的(如果信号在正确的时刻传递)。

查看man 7 signal手册页,特别是异步信号安全函数下的部分:

A signal handler function must be very careful, since processing elsewhere may be interrupted at some arbitrary point in the execution of the program. POSIX has the concept of "safe function". If a signal interrupts the execution of an unsafe function, and handler calls an unsafe function, then the behavior of the program is undefined.

请注意,printf()绝对不是异步信号安全函数;因此行为是未定义的。

在一般情况下,解决方案并不简单,因为没有异步信号安全锁定原语(除了sem_post(),它本身不足以实现此目的,并且文件锁必须在周围使用所有printf()调用)。通用的、可移植的解决方案是使用pipe()中的unistd.h创建一个管道,并使用write()将输出写入管道,然后让主程序从管道中读取并“转发”内容。写入短于PIPE_BUF的 POSIX 保证是原子的,PIPE_BUF至少为 512(Linux 中为 4096)——有关详细信息,请参阅 man 7 pipe ——因此在实践中这也仅限于 512 字节或更短的消息用于可移植代码。

通常,在这种特殊情况下,只需设置全局printf()变量即可替换信号处理程序中的volatile sigatomic_t。然后主循环可以简单地检查(并清除)全局变量并输出消息本身。

虽然标志变量方法可能会丢失快速重复的SIGUSR1信号,但这是无关紧要的,因为您总是会丢失快速重复的SIGUSR1信号:一次只能有一个待处理信号,因此重复在第一个信号和处理它之间发生的信号根本不会传递! (如果您要使用排队的实时信号,如SIGRTMIN+0,您可以通过在主循环中使用原子内置信号(如__sync_fetch_and_and(variable,0)__atomic_exchange_n(variable,0,__ATOMIC_SEQ_CST),以及__sync_fetch_and_add(variable,1)或“信号处理程序中的__atomic_fetch_add(variable,1,__ATOMIC_SEQ_CST);两者前面都有__sync_synchronize()__atomic_signal_fence(__ATOMIC_SEQ_CST)调用,以确保更改立即生效/对另一个可见。但在这种情况下,您无需担心原子操作。)

对于sigset()sigprocmask()也有一个有趣的极端情况 - 不是竞争条件。进程从其父进程继承其信号掩码,默认情况下不阻止SIGUSR1。除非进行处理,否则它会导致进程终止。因此,根据继承的信号掩码,在SIGUSR1调用之前传递的sigset()信号要么被阻止,要么导致进程终止。 (但是,如果set包含SIGUSR1;即SIGUSR1被阻止,那么就会出现竞争条件,除非sigprocmask()sigset()之前被调用。但是,由于set ”为空,sigset()最好在sigprocmask()之前调用。)

关于c - C 信号处理程序中的竞争条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11816068/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com