信号安全使用sem_wait()/ sem_post()

时间:2009-06-01 23:24:21

标签: c posix

我正在尝试在Linux上创建一个包装器,它可以控制一次允许多少次并发执行。为此,我使用系统范围的计数信号量。我创建信号量,执行sem_wait(),启动子进程,然后在子进程终止时执行sem_post()。没关系。

问题是如何安全地处理发送到此包装器的信号。如果它没有捕获信号,则命令可能会在不执行sem_post()的情况下终止,从而导致信号量计数永久减少1。所以,我创建了一个执行sem_post()的信号处理程序。但是,仍有一个问题。

如果在执行sem_wait()之前附加了处理程序,则信号可能会在sem_wait()完成之前到达,导致sem_post()在没有sem_wait()的情况下发生。如果我在设置信号处理程序之前执行sem_wait(),则可以反过来。

明显的下一步是在处理程序和sem_wait()的设置过程中阻止信号。这是我现在拥有的伪代码:

void handler(int sig)
{
  sem_post(sem);
  exit(1);
}

...
sigprocmask(...);   /* Block signals */
sigaction(...);     /* Set signal handler */
sem_wait(sem);
sigprocmask(...);   /* Unblock signals */
RunChild();
sem_post(sem);
exit(0);

现在的问题是sem_wait()可以阻止,在此期间,信号被阻止。试图杀死进程的用户可能最终诉诸“kill -9”,这是我不想鼓励的行为,因为无论如何我都无法处理这种情况。我可以使用sem_trywait()一小段时间并测试sigpending(),但这会影响公平性,因为不再保证等待最长信号量的进程将在下一次运行。

这里有一个真正安全的解决方案,可以让我在信号量采集过程中处理信号吗?我正在考虑求助于“我有信号量”全局并删除信号阻塞,但这不是100%安全,因为获取信号量并设置全局不是原子的,但可能比等待时阻塞信号更好。

3 个答案:

答案 0 :(得分:7)

您确定sem_wait()会导致信号被阻止吗?我不认为是这种情况。 man page for sem_wait()表示EINTR错误代码如果被信号中断则从sem_wait()返回。

您应该能够处理此错误代码,然后您的信号将被接收。您是否遇到过没有收到信号的情况?

我会确保您处理sem_wait()可以返回的错误代码。虽然可能很少见,但如果你想100%确定你想要100%的基数。

答案 1 :(得分:0)

您确定正确接近问题吗?如果您想等待孩子终止,您可能需要使用waitpid()系统调用。正如您所观察到的那样,如果孩子接收到信号,那么期望孩子做sem_post()是不可靠的。

答案 2 :(得分:0)

我知道这已经过时了,但为了那些仍在阅读Google礼貌的人的利益......

这个问题的最简单(也是唯一?)强大的解决方案是使用System V信号量,它允许客户端以一种内核自动返回的方式获取信号量资源。无论过程是如何排除的。< / p>