假设我有一个标志来指示我用信号启用的退出条件。然后我可以将以下处理程序附加到 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 条件之后但在接受调用之前传递。然后信号处理程序将设置finished
为true,但在执行恢复后,accept
将被调用并无限期阻塞。我怎样才能避免这种情况并确保我总是能够用我的信号终止循环?
假设我仍然想使用信号来控制它,我可以想到两种可能的解决方案。第一个是打开一些警报,如果第一次错过信号,它会在一段时间后重新发出信号。第二个是在套接字上设置超时,以便在一段时间后接受返回,以便可以再次检查标志。但是这些解决方案更像是变通方法(特别是因为我在第二个解决方案中更改了接受的阻塞行为),如果有一些更清洁和更直接的解决方案,我想改用它。