我有一个使用pthreads的Unix守护程序。一个线程循环运行,使用recvmsg读取网络数据包。当守护程序接收到信号时,将设置一个标志,告诉所有线程退出其循环并退出。但是,“监听”线程在下一个数据包到达并返回recvmsg之前,不会检查该标志,这可能需要一些时间。

使用SIGINTpthread_kill传递到“监听”线程会使它脱离recvmsg,但是它还会调用信号处理程序,该信号处理程序通过在控制台上按Ctrl + C来处理发送的中断。那是不需要的。强制recvmsg提前返回的另一种方法是关闭正在监听的套接字,但是我认为必须有更好的方法。你知道这是什么吗?

如果有所不同,则仅在Linux上使用此守护程序。

最佳答案

三个想法:

构想1:
为什么没有另一个信号?信号SIGUSR1SIGUSR2仅存在于用户定义的信令中。如果您已经设置了信号处理程序并且通常对它们的使用感到满意,那么这可能是最简单的方法。

构想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_eventsselectpollepoll_wait。设置等待列表以同时包含套接字和附加文件,例如管道,unix域套接字或POSIX消息队列(在Linux中是文件)。

要取消套接字读取器线程,请在取消文件对象上执行write。然后,让阅读器检查从轮询/轮询/选择中唤醒时是否能够读取该fd。

如果有多个正在处理recvmsg的事物实例,那么您应该能够使用一个这样的文件来唤醒所有线程,只要确保使用epoll时使用级别触发而不是边缘触发即可。

如果您不确定要使用这三个调用中的哪一个,建议您从poll开始,如果真的很了解,请仅使用select;如果您知道自己需要可伸缩性,则仅使用epoll

关于c - 如何唤醒在recvmsg()中休眠的pthread?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29237539/

10-13 09:30