首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何唤醒处于recvmsg()中的线程?

如何唤醒处于recvmsg()中的线程?
EN

Stack Overflow用户
提问于 2015-03-24 16:07:49
回答 4查看 3K关注 0票数 2

我有一个小小的Unix守护进程,它使用p线程。一个线程在一个循环中运行,使用recvmsg读取网络数据包。当守护进程接收到信号时,将设置一个标志,通知所有线程从它们的循环中断开并退出。但是,“侦听”线程在下一个数据包到达并recvmsg返回之前从不检查标志,这可能需要一些时间。

使用SIGINT向“侦听”线程传递pthread_kill使其脱离recvmsg,但它也调用信号处理程序,该处理程序处理通过在控制台按Ctrl+C发送的中断。这是多余的。另一种迫使recvmsg提前返回的方法是关闭它正在监听的套接字,但我认为一定有更好的方法。你知道这是什么吗?

这个守护进程只在Linux上使用,如果它有区别的话。

EN

Stack Overflow用户

发布于 2015-03-24 18:53:14

将空信号处理程序安装到未使用的POSIX实时信号,SIGRTMIN+0SIGRTMAX-0,并使用pthread_kill()将该信号发送到在recvmsg()中阻塞的线程。实时信号排队(可靠),而标准信号不排队。这意味着,如果使用实时信号,则同时中断两个不同的线程,但如果使用正常信号(如SIGUSR1),则可能会失败。

是将信号传递给信号处理程序,从而中断库函数或系统调用--即使信号处理程序函数的主体为空。(当然,假设您使用没有sigaction()标志的SA_RESTART安装信号处理程序。有关详细信息,请参阅man 7 signal,在“信号处理程序中断系统调用和库函数”下。

使用这种方法(使用信号中断阻塞I/O函数)可能遇到的一个问题是,信号是在目标线程实际阻塞I/O函数之前提前发出的。那扇窗户是无法避免的,你只需要处理好它。

就我个人而言,我喜欢使用一个专门的线程维护超时结构,比如

代码语言:javascript
运行
复制
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()选择。

票数 1
EN
查看全部 4 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29237539

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档