在大多数POSIX线程的实现中,在新创建的线程能够运行应用程序代码之前,需要对其进行一些初始化操作,以使其处于一致的状态。这可能涉及在线程结构中解锁锁定、在使用“线程寄存器”的实现中初始化它,初始化线程本地数据(无论是编译器级别的TLS还是POSIX线程特定数据)等。我找不到明确的保证所有这些初始化将在线程接收任何信号之前完成的证据;最接近的是2.4.3中的内容:
有一件让我困扰的事情是,我已经阅读了很多glibc/nptl源代码,但无法找到任何显式的同步机制来防止信号在新创建的线程尚未完全初始化时被处理。我期望调用
大概率上,其中一些函数(至少有以下表格定义了一组应为异步信号安全的函数。因此,应用程序可以在信号捕获函数中不受限制地调用它们:
...
fork
函数,必须检查由pthread_atfork
函数建立的全局状态)依赖于线程处于一致、已初始化状态。有一件让我困扰的事情是,我已经阅读了很多glibc/nptl源代码,但无法找到任何显式的同步机制来防止信号在新创建的线程尚未完全初始化时被处理。我期望调用
pthread_create
的线程在调用clone
之前阻止所有信号,并且在初始化完成后,新线程解除阻塞,但我找不到任何相关代码,也在strace
输出中没有看到它。
pthread_atfork()
处理程序的情况下从信号处理程序中调用fork()
,那么你必须非常了解你在做什么(并且信任你的库实现)!特别是如果(通常情况下)预分配处理程序获取一堆锁以确保它们所代表的数据在分叉之前是一致的 - 任何这些锁都可能原则上被线程持有(或更糟糕的是,在正在获取这些锁的过程中)处理信号的线程,这意味着数据将不可避免地不一致(或进程可能会死锁!)。真是开心极了 :-) - psmearspthread_atexit
处理程序,那会发生什么。调用应用程序可能期望fork
是异步信号安全的(如文件所述),并从信号处理程序中调用它。我猜通过这个思想实验得出结论的意图是揭示了一个透明度 - 线程使用 - 由库创建的模型中的缺陷。pthread_atfork
被引入来解决这个问题。 - R.. GitHub STOP HELPING ICEpthread_atexit
而不是pthread_atfork
。 :-) - R.. GitHub STOP HELPING ICE