在信号处理的上下文中到底哪些变量需要 sig_atomic_t ?

2023-12-13

这是一个简单的玩具程序,使用volatile sig_atomic_t.

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

#define UNUSED(x) (void) (x)

volatile sig_atomic_t quit;

void sigusr1_handler(int sig)
{
    UNUSED(sig);
    write(1, "handler\n", 8);
    quit = 1;
}

int main()
{
    struct sigaction sa;

    sa.sa_handler = sigusr1_handler;
    sa.sa_flags = 0;
    sigemptyset(&sa.sa_mask);

    if (sigaction(SIGUSR1, &sa, NULL) == -1) {
        perror("sigaction");
        return 1;
    }

    quit = 0;
    while (!quit)
        ;

    printf("Exiting ...\n");
    return 0;
}

我想我知道为什么volatile sig_atomic_t是必要的quit这个特定程序中的变量。

  1. Without volatile,编译器可能会优化while (!quit) ;到无限循环。它没有发现循环修改quit,因此假设quit永远保留0.
  2. 更新至quit或读过quit应该发生在一条机器指令中。如果需要多条机器指令来更新或读取quit,那么如果在更新正在进行时调用信号处理程序,则信号处理程序中的读取可能会看到不一致的值quit.

到目前为止我的说法正确吗?如果没有,请纠正我的答案。

现在我想学习一个通用规则sig_atomic_t在信号处理的上下文中是必要的。乔纳森·莱弗勒(Jonathan Leffler)在评论中解释说,提供概括并不容易。

您能否提供一个已知场景的列表,其中变量需要定义为sig_atomic_t从C标准的角度来看?它不必是详尽的清单。经验不足的开发人员在编写带有信号处理代码的 C 软件时可以参考该列表。


您能否提供一个已知场景的列表,其中变量需要定义为sig_atomic_t从C标准的角度来看?

有 2 个相关部分c99 spec:

(§7.14 p2)
[The sig_atomic_ttype] 是对象的(可能是 volatile 限定的)整数类型,即使存在异步中断,也可以将其作为原子实体进行访问

(§7.14.1.1 p5)
如果该信号不是由于调用abort or raise函数中,如果信号处理程序引用任何具有静态存储持续时间的对象,而不是将值分配给声明为的对象,则行为未定义volatile sig_atomic_t, ...

“静态存储时间”定义为:

(§6.2.4 p3)
其标识符通过外部或内部链接或存储类说明符声明的对象static has 静态存储时间。它的生命周期是程序的整个执行过程,并且其存储的值仅在程序启动之前初始化一次。

简而言之,您需要使用volatile sig_atomic_t变量是否可以异步访问(即,在信号处理程序内部和外部都可以访问该变量)。此外,访问非对象是未定义的行为volatile sig_atomic_t具有静态存储持续时间的变量。未定义的行为意味着不仅变量的值可能不一致,程序还可能完全执行其他操作(例如段错误)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在信号处理的上下文中到底哪些变量需要 sig_atomic_t ? 的相关文章

随机推荐