在信号处理的上下文中,究竟哪些变量需要是sig_atomic_t?

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

 #include  #include  #include  #include  #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. 如果没有volatile ,编译器可以优化while (!quit) ; 无限循环。 它没有找到循环修改quit ,因此它假定quit始终保持为0
  2. quit或读取quit的更新应在单个机器指令中进行。 如果需要多个机器指令来更新或读取quit ,那么如果在进行更新时调用信号处理程序,则信号处理程序中的读取可能会在quit看到不一致的值。

到目前为止我是否正确? 如果没有,请在答案中纠正我。

现在我想学习在信号处理的上下文中何时需要sig_atomic_t的通用规则。 Jonathan Leffler在评论中解释说提供概括并不容易。

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

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

c99规范中有2个相关部分:

(§7.14p2)
[ sig_atomic_t类型]是可以作为primefaces实体访问的对象的(可能是volatile限定的)整数类型,即使存在异步中断也是如此

(§7.14.1.1p5)
如果信号不是作为调用abortraise函数的结果发生的,那么如果信号处理程序引用具有静态存储持续时间的任何对象,而不是通过将值volatile sig_atomic_t声明为volatile sig_atomic_t的对象,则行为是未定义的,…

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

(§6.2.4p3)
标识符使用外部或内部链接声明的对象,或者使用存储类说明符static声明的对象具有静态存储持续时间 。 它的生命周期是程序的整个执行,它的存储值只在程序启动之前初始化一次。

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