Сигнальное безопасное использование sem_wait () / sem_post () - PullRequest
4 голосов
/ 02 июня 2009

Я пытаюсь создать оболочку в Linux, которая контролирует, сколько одновременных выполнений чего-либо разрешено одновременно. Для этого я использую общесистемный счетный семафор. Я создаю семафор, делаю 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% безопасно, так как получение семафора и установка глобального не атомарны, но могут быть лучше, чем блокировка сигналов во время ожидания. *

Ответы [ 3 ]

7 голосов
/ 02 июня 2009

Вы уверены, что sem_wait() вызывает блокировку сигналов? Я не думаю, что это так. Страница man для sem_wait() сообщает, что код ошибки EINTR возвращается из sem_wait(), если он прерывается сигналом.

Вы должны быть в состоянии обработать этот код ошибки, и тогда ваши сигналы будут получены. Вы сталкивались с случаем, когда сигналы не были получены?

Я бы позаботился о том, чтобы вы обрабатывали коды ошибок, которые sem_wait() может вернуть. Хотя это может случаться редко, если вы хотите быть на 100% уверены, что хотите покрыть 100% своих баз.

0 голосов
/ 12 октября 2012

Я знаю, что это старая версия, но для тех, кто все еще читает эту любезность Google ...

Самое простое (и единственное?) Надежное решение этой проблемы - это использование семафора System V, который позволяет клиенту получать ресурс семафора способом, который автоматически возвращается ядром. 1003 *

0 голосов
/ 02 июня 2009

Вы уверены, что правильно подходите к проблеме? Если вы хотите дождаться завершения дочернего процесса, вы можете использовать системный вызов waitpid(). Как вы заметили, ожидать от ребенка sem_post(), если он может получать сигналы, ненадежно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...