C语言 POSIX线程/信号:确定信号被传递到哪个线程的可移植方法



我有一个多线程服务器(使用POSIX线程),每个持久连接一个线程。在其中一个线程中,连接的另一端关闭,导致SIGPIPE被传递。是否有一个(最好是可移植的)来确定哪个线程(以及哪个连接)发生了这种情况,这样我就可以让我的信号处理程序要么自己做线程/连接清理工作,要么设置一个标志,以便主线程和工作线程分别看到它们需要在以后做?

编辑:我想知道我是否可以使用&errno,将其存储在一个全局数组中,并将其与服务器的线程标识符相关联,然后在信号处理程序中搜索&errno。线程的特定errno对信号处理程序是否可见?我的理解是如何线程安全errno工作,甚至在球场?

我不这么认为。对于多线程服务器,一个更好的解决方案是抑制SIGPIPE信号(通过调用signal(SIGPIPE, SIG_IGN)作为程序启动例程的一部分),然后让线程处理send()返回的错误值(-1/EPIPE)。

信号和多线程不能很好地混合。

您可以安全地在信号处理程序中使用pthread_self。它是异步信号安全的。

这个答案留给子孙后代。从技术上讲,我不推荐这种方法。其他的答案和评论,建议一个不同的方法,会更好地实施。

在提出这个问题的时候,pthread_self的安全性并不一定明显。POSIX:2008技术更正1,日期为2013年(在提出这个问题的两年后),澄清了pthread_self是显式异步信号安全的,如Linux signal(7)手册页所述。

与此相关,您在评论中提到您不确定是否"内核将[SIGPIPE]发送给任何未被阻塞的线程"。这是一个很好的问题——它是一个进程导向的信号还是一个线程导向的信号?——谢天谢地,是放错了地方。内核生成的SIGPIPE是"同步生成"的信号,用于响应某些I/O调用,并发送给调用线程。在POSIX:2001的勘误2(2004)中明确澄清了这一点,说响应write的SIGPIPE是"发送到线程"(强调添加)。

我的方法是让SIGPIPE的信号处理程序只是将其线程ID写入全局变量,并使用一些其他机制将此信号发送给应该处理它的线程。

使用全局变量(声明为thread-local)来存储线程id,在线程创建时初始化它,并在线程的信号处理程序中引用它。

关于这方面的GCC详细信息,请参阅这里:http://gcc.gnu.org/onlinedocs/gcc/Thread_002dLocal.html或更一般的在这里:http://en.wikipedia.org/wiki/Thread-local_storage

最新更新