假设我有一个标志来指示我要通过信号启用的退出条件。然后,我可以将以下处理程序附加到SIGUSR1上。
volatile sig_atomic_t finished = 0;
void catch_signal(int sig)
{
finished = 1;
}
然后,我使用该标志来确定特定循环应何时结束。在这种特殊情况下,我正在运行一个线程(但我认为我的问题也适用于没有线程的情况,因此请不要专注于该部分)。
void *thread_routine(void *arg)
{
while (!finished) {
/* What if the signal happens here? */
if ((clientfd = accept(sockfd, &remote_addr, &addr_size)) == -1) {
if (errno == EINTR)
continue;
/* Error handling */
}
handle_client(clientfd);
}
}
该循环应该继续运行,直到我发出SIGUSR1信号为止。当它收到信号时,我希望它尽快正常停止。因为我有一个阻塞接受调用,所以没有使循环浪费CPU周期的问题,这很好,并且信号可以随时中断阻塞接受并导致循环终止。
如代码中的注释所示,问题是信号可能在while条件之后但在accept调用之前传递。然后,信号处理程序将
finished
设置为true,但是在恢复执行后,accept
将被调用并无限期地阻塞。如何避免这种情况,并确保始终能够使用信号终止循环?假设我仍然想使用信号来控制此情况,我可以想到两种可能的解决方案。第一个是打开一些警报,如果第一次错过信号,过一会儿就会重新发出信号。第二个方法是在套接字上设置超时,以便在一段时间后accept返回,以便可以再次检查该标志。但是这些解决方案更像是变通办法(尤其是因为我在第二个解决方案中更改了accept的阻塞行为),如果有更简洁,更直接的解决方案,我想改用它。
最佳答案
在这种情况下可以使用Self-Pipe Trick。
您打开管道,并使用select
在pipefd和sockfd上等待。处理程序将一个char写入管道。选择之后,检查fd集有助于您确定是否可以接受。
关于c - 结合使用sig_atomic_t标志和阻止调用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19700263/