我有一个使用pthreads的Unix守护程序。一个线程循环运行,使用recvmsg
读取网络数据包。当守护程序接收到信号时,将设置一个标志,告诉所有线程退出其循环并退出。但是,“监听”线程在下一个数据包到达并返回recvmsg
之前,不会检查该标志,这可能需要一些时间。
使用SIGINT
将pthread_kill
传递到“监听”线程会使它脱离recvmsg
,但是它还会调用信号处理程序,该信号处理程序通过在控制台上按Ctrl + C来处理发送的中断。那是不需要的。强制recvmsg
提前返回的另一种方法是关闭正在监听的套接字,但是我认为必须有更好的方法。你知道这是什么吗?
如果有所不同,则仅在Linux上使用此守护程序。
最佳答案
三个想法:
构想1:
为什么没有另一个信号?信号SIGUSR1
和SIGUSR2
仅存在于用户定义的信令中。如果您已经设置了信号处理程序并且通常对它们的使用感到满意,那么这可能是最简单的方法。
构想2:
按照其他建议发送虚拟数据包。
理念3:
如果您确实想避免发送数据包,请尝试使用非阻塞I/O,以使recvmsg完全不会阻塞(请参阅MSG_DONTWAIT
)。
而是,调用epoll | poll | select
来阻止套接字接收事件和另一个文件描述符。
这样的循环看起来像这样:
while(1){
recvmsg();
do_stuff();
}
成为:
while(1){
wait_for_events();
if( /* FD used for cancellation is readable */ )
break;
else
recvmsg();
do_stuff();
}
其中
wait_for_events
是select
,poll
或epoll_wait
。设置等待列表以同时包含套接字和附加文件,例如管道,unix域套接字或POSIX消息队列(在Linux中是文件)。要取消套接字读取器线程,请在取消文件对象上执行
write
。然后,让阅读器检查从轮询/轮询/选择中唤醒时是否能够读取该fd。如果有多个正在处理
recvmsg
的事物实例,那么您应该能够使用一个这样的文件来唤醒所有线程,只要确保使用epoll
时使用级别触发而不是边缘触发即可。如果您不确定要使用这三个调用中的哪一个,建议您从
poll
开始,如果真的很了解,请仅使用select
;如果您知道自己需要可伸缩性,则仅使用epoll
。关于c - 如何唤醒在recvmsg()中休眠的pthread?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29237539/