我有一个小小的Unix守护进程,它使用p线程。一个线程在一个循环中运行,使用recvmsg
读取网络数据包。当守护进程接收到信号时,将设置一个标志,通知所有线程从它们的循环中断开并退出。但是,“侦听”线程在下一个数据包到达并recvmsg
返回之前从不检查标志,这可能需要一些时间。
使用SIGINT
向“侦听”线程传递pthread_kill
使其脱离recvmsg
,但它也调用信号处理程序,该处理程序处理通过在控制台按Ctrl+C发送的中断。这是多余的。另一种迫使recvmsg
提前返回的方法是关闭它正在监听的套接字,但我认为一定有更好的方法。你知道这是什么吗?
这个守护进程只在Linux上使用,如果它有区别的话。
发布于 2015-03-24 18:53:14
将空信号处理程序安装到未使用的POSIX实时信号,SIGRTMIN+0
到SIGRTMAX-0
,并使用pthread_kill()
将该信号发送到在recvmsg()
中阻塞的线程。实时信号排队(可靠),而标准信号不排队。这意味着,如果使用实时信号,则同时中断两个不同的线程,但如果使用正常信号(如SIGUSR1
),则可能会失败。
是将信号传递给信号处理程序,从而中断库函数或系统调用--即使信号处理程序函数的主体为空。(当然,假设您使用没有sigaction()
标志的SA_RESTART
安装信号处理程序。有关详细信息,请参阅man 7 signal
,在“信号处理程序中断系统调用和库函数”下。
使用这种方法(使用信号中断阻塞I/O函数)可能遇到的一个问题是,信号是在目标线程实际阻塞I/O函数之前提前发出的。那扇窗户是无法避免的,你只需要处理好它。
就我个人而言,我喜欢使用一个专门的线程维护超时结构,比如
struct timeout {
pthread_t who;
struct timespec when; /* Using CLOCK_MONOTONIC */
volatile int state;
};
每个线程都可以获取和释放--我发现一个线程可以同时保持多个超时特别有用--以及一个简单的原子函数来检查状态(用于例如循环条件)。
诀窍是,当超时最初触发时,由于前面提到的问题时间窗口,它不会被删除。相反,我喜欢标记超时“已过”,并在几毫秒后重新启动它。这会重复执行,直到目标线程释放超时为止。(每次触发超时时,我都会向目标线程发送一个POSIX实时信号,并安装了一个空信号处理程序函数。)
这样,即使您的recv()
/send()
循环偶尔错过信号,它们也会很快被通知。
如果您曾经取消线程,您还需要安装一个线程清理处理程序,该处理程序释放线程拥有的所有超时。否则,您可能会“泄漏”超时结构。
如果您使用clock_gettime()
和pthread_cond_timedwait()
,等待一个新的超时条目(由其他线程添加)或一个现有的超时经过,超时管理线程将非常轻量级,并且不会占用太多的内存或CPU时间。请注意,您可以使用CLOCK_MONOTONIC
,如果您创建新的超时值添加条件变量的属性集,该时钟通过pthread_condattr_setclock()
选择。
https://stackoverflow.com/questions/29237539
复制相似问题