这实际上是两个问题,但我认为将它们结合起来会更好。
我们正在使用异步TCP连接的客户端。这个想法是程序将阻塞,直到从服务器收到某些消息,这将调用一个SIGPOLL处理程序。我们正在使用繁忙的等待循环,基本上是:
var = 1
while (var) usleep(100);
//...and somewhere else
void sigpoll_handler(int signum){
......
var = 0;
......
}
我们希望使用更可靠的东西,就像信号量一样。问题是,当一个线程在信号量上被阻塞时,信号是否会通过?特别是考虑到信号在切换回用户级别时会被传送;如果这个过程偏离了这个过程,它会怎么样?
附带问题(出于好奇):
没有" usleep(100)"程序永远不会超过while循环,虽然我可以验证变量是否在处理程序中设置。这是为什么?打印也改变了它的行为。
干杯!
答案 0 :(得分:2)
[评论太久了]
从信号处理程序内部访问var
会调用未定义的行为(至少对于符合POSIX的系统)。
来自the related POSIX specification:
[...]如果进程是单线程的并且执行了信号处理程序,那么如果信号处理程序引用除静态存储持续时间之外的任何对象,则行为是未定义的。为声明为 volatile sig_atomic_t [...]
的对象赋值
因此应定义var
:
volatile sig_atomic_t var;
繁忙的等待while
- 循环,可以通过一次阻塞pause()
来代替,因为它会在接收到信号时返回。
来自the related POSIX specification:
pause()函数应暂停调用线程,直到传递一个信号,该信号的动作是执行信号捕获功能或终止进程。
使用pause()
,顺便说一句,将使var
这样的任何全局标志变得冗余,而不是说不必要。
答案 1 :(得分:1)
简短的回答:是的,信号通过良好的实施将会很好。
如果您打算使用信号量来控制程序的流程,那么您希望将监听功能放在一个孩子身上,并将实际数据处理放在另一个孩子身上。这将使并发公平性落在操作系统的手中,这将确保您的信号监听线程有机会检查具有一定规律性的信号。它应该永远不会真正地离开会员队,"但是要骑车穿过跑道上的位置。
如果它有助于你思考它,你现在所拥有的似乎基本上是一个信号量本身非常粗略的实现 - 一个共享变量,其值将阻止一个代码块执行,直到另一个代码块清除它。关于系统级别的信号量,没有任何内在瘫痪的东西。
我有点想知道为什么你用来监听SIGPOLL的任何功能都不会做自己的阻塞。我见过的大多数实用工具都会在返回值之前停止调用线程。基本上它们为您处理并发性,您可以编写代码,就像处理正常的同步程序一样。
关于usleep循环:我必须看看优化器在做什么,但我认为基本上有两种可能性。我认为这不太可能,但可能是无体循环正在编译成实际上没有检查值变化而只是循环的东西。更可能的是,缺乏任何正文步骤会破坏底层并发处理,并且循环执行得如此之快以至于没有其他任何东西可以运行 - 队列被循环迭代和信号淹没processsing无法在edgewise中获得一个单词。您可以尝试观看几个小时,看看是否有任何变化;从理论上讲,如果它只是一个并发问题,那么所涉及的随机因素就可以通过几十亿的机会自行清除该块。