Я пытаюсь создать оболочку в Linux, которая контролирует, сколько одновременных исполнений чего-то разрешено сразу. Для этого я использую системный счетный семафор. Я создаю семафор, делаю sem_wait()
, запускаю дочерний процесс, а затем делаю sem_post()
, когда ребенок завершается. Это нормально.Безопасное использование сигнала sem_wait()/sem_post()
Проблема заключается в том, как безопасно обрабатывать сигналы, отправленные в эту оболочку. Если он не поймает сигналы, команда может завершиться без выполнения sem_post()
, в результате чего количество семафоров будет постоянно уменьшаться на единицу. Итак, я создал обработчик сигнала, который делает 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
Это сработало. Я удалил блокировку сигналов и изменил обработчик сигнала, чтобы просто установить глобальный смысл, когда пришло время уйти. Если sem_wait() возвращает ошибку, то я прекращаю то, что отлично, и сохраняет счет семафора. Если я жду ребенка, я также тестирую timeToQuit global. Если пришло время уйти, я убиваю его и делаю sem_post(), который сохраняет счет семафора. Благодарю. Это должно быть безопасным сигналом, игнорируя kill -9. – Jeremy