我想在Linux上创建一个包装器,它控制一次允许多少个并发执行的东西。为此,我正在使用系统范围计数信号量。我创建信号量,执行sem_wait()
,启动子进程,然后在子进程结束时执行sem_post()
。没事儿。信号安全使用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%安全,这不是原子性的,但可能比等待时阻止信号更好。
对不起,如果我不清楚。sem_wait()不会像您所说的那样导致信号被阻塞,但我正在使用sigprocmask()来阻止它们。但是,我认为你有正确的解决方案,即查看EINTR错误代码,这意味着处理程序不应该退出,但设置一些标志来表示“退出时间”。我会测试一下。谢谢。 – Jeremy 2009-06-01 23:46:29
工作。我删除了信号的阻塞,并将信号处理程序更改为设置全局含义,现在是时候退出了。如果sem_wait()返回一个错误,那么我退出这是很好,并保留信号计数。如果我在等孩子,我也测试timeToQuit global。如果是时候退出,我杀了孩子,并做一个sem_post(),它保留了信号计数。谢谢。这应该是信号安全的,忽略kill -9。 – Jeremy 2009-06-02 00:04:45