Mat*_*ano 3 c++ signals c++11 c++14
假设我有这个功能:
int my_thread_id(){
static int counter {0};
thread_local int tid{++counter};
return tid;
}
Run Code Online (Sandbox Code Playgroud)
即使在第一次调用时,此函数 (my_thread_id) 是否异步信号安全?
这个答案可以被认为是 ildjarn 给出的答案的附录。严格来说 C++ 14 标准时,使用信号处理程序中的 thread_local 存储数据会导致未定义的行为。
然而,在某些平台上,这种使用可能是允许的。例如,大多数 POSIX 系统通过使用为每个线程分配的特殊数据段(如堆栈)来实现线程本地存储。详细解释请参考该文档。在这种情况下,对线程本地数据的访问是异步信号安全的,因为它不涉及任何锁。
但是,信号处理程序读取或写入的数据可能仍然不一致,除非仅访问原子或使用 来隔离访问std::atomic_signal_fence。原因是编译器不知道信号处理程序何时会中断执行,因此可能会重新排序读写指令。std::atomic_signal_fence禁止这种重新排序,并且 CPU 重新排序不是问题,因为执行发生在同一线程内,并且仅当结果(线程内)与指令已按顺序执行相同时才允许 CPU 重新排序指令。
除了 std::atomic_signal_fence 之外,使用 std::atomic 类型的变量也是安全的,只要它们是无锁的(如 std::is_lock_free 所示)。
在 Linux(我相信大多数其他 POSIX 平台)上,信号是否被分派到特定线程的问题取决于该信号的生成方式以及信号的确切类型。例如,SIGSEGV和SIGBUS总是被分派到导致错误并产生信号的线程。在这种情况下,使用线程本地存储可能是从此类错误中恢复的便捷方法。然而,没有办法在保持代码可移植到支持 C++ 标准的所有平台的同时做到这一点。