sigprocmask во время выполнения сигнала - PullRequest
2 голосов
/ 17 ноября 2011

В настоящее время я исследую использование sigprocmask для блокировки определенных сигналов (в данном случае SIGALRM и SIGCHLD), когда выполняется критический сегмент кода. Оба обработчика сигналов, связанные с этими сигналами, получат доступ и изменят центральную структуру данных, поэтому крайне важно, чтобы я запретил им доступ к ней, пока над ней работает основной процесс.

В настоящий момент мой план состоит в том, чтобы просто отключить эти сигналы в начале критической секции кода, а затем снова включить их в конце.

void criticalFunction(void) {
    // disable signals with sigprocmask
    // critical code
    // enable signals with sigprocmask
}

Однако обработчик сигналов, которые будут заблокированы, также вызывает criticalFunction. Что произойдет, когда они вызовут функцию sigprocmask и включат блокировку для своих собственных сигналов? Будут ли они останавливаться или продолжать выполнять? (Или какое-то третье условие ..)

Единственное замечание, которое мне удалось найти по этому поводу, это следующее:

Если sigprocmask () вызывается в обработчике сигнала, возвращаясь из Обработчик может отменить работу sigprocmask (), восстановив оригинал маска ожидающего сигнала. (http://www.mkssoftware.com/docs/man3/sigprocmask.3.asp)

(Это дополнительный вопрос к моему предыдущему вопросу: Обработчик сигнала, обращающийся к структуре данных очереди (состояние гонки?) )

Ответы [ 2 ]

4 голосов
/ 17 ноября 2011

Имейте в виду, что поведение по умолчанию внутри обработчика сигнала заключается в блокировке обрабатываемого сигнала.Кроме того, при вызове функций внутри обработчиков сигналов требуется вызывать только безопасные функции.С учетом сказанного, sigprocmask() является сигнально-безопасной функцией , и если вы используете ее для блокировки того же сигнала, который блокируется обработчиком сигнала, который вызывается внутри, то на самом деле ничего не происходитслучиться ... вы останетесь с той же маской сигнала, которая у вас есть в настоящее время.Единственное отличие состоит в том, что внутри обработчика сигналов гарантированно блокируются только сигналы для SIGALRM или SIGCHLD (это будет зависеть от того, в каком обработчике сигналов вы находитесь), где-как при вызове sigprocmask() чтобы заблокировать эти специфические сигналы, оба сигнала будут заблокированы после вызова.

Следует обратить внимание на вторую часть кода в criticalFunction, когда вы пытаетесь вызвать sigprocmask() на включить сигналы, которые в данный момент заблокированы в маске сигналов.Это может создать ситуацию, когда вы в конечном итоге получаете уровень повторного входа в вызовы вашего обработчика сигналов.Другими словами, включение сигнала для обработчика сигнала, в котором вы находитесь, может означать, что перед выходом из текущего обработчика сигнала будет пойман другой SIGALRM или SIGCHLD, и вы снова войдете в обработчик сигнала сноваобрабатывать этот недавно пойманный сигнал.Пока вы активируете сигналы после каких-либо критических обновлений, тогда я думаю, что вы будете в порядке с этой повторяющейся ситуацией, но просто для того, чтобы избежать опасностей, вы можете включить сигналы только в criticalFunction вв самом конце criticalFunction, а не где-то посередине, и когда вы возвращаетесь из criticalFunction, не делайте ничего, что не было бы асинхронным ... вы должны предположить, что любой код после возвратавторой sigprocmask() может выполняться не по порядку (т. е. он может выполняться после того, как второй сигнал был перехвачен и его обработчик сигнала был запущен).

Вам может понадобиться только "остановка"«если вы пытались вызвать что-то из семейства exec или что-то в этом роде внутри вашего обработчика сигналов.Что произойдет, так это то, что недавно наложенный процесс унаследует маску сигналов от текущего процесса, поэтому, если текущий процесс заблокировал определенные сигналы, они также будут заблокированы в новом процессе.Таким образом, если новый процесс предполагал, что сигналы были разблокированы, ваш обработчик сигналов в новом процессе никогда не запустится.

Кстати, одно предупреждение: не смешивайте сигналы и потоки !Вы упоминаете «основной процесс» в своем вопросе ... Я надеюсь, это не значит, что вы пытаетесь смешивать сигналы и потоки.Если это так, это требует очень специфической идиомы, в противном случае вы создадите разного рода хаос.

2 голосов
/ 17 ноября 2011

Ваш план неверен, когда вы говорите, что «обработчики сигналов [...] вызывают criticalFunction».Обработчики сигналов никогда не должны выполнять какую-либо серьезную работу.Они не предназначены для этого.

Единственное, что вы должны разумно сделать из обработчика сигнала, - это изменить переменную типа sigatomic_t.Обычно это используется для установки флага, а оставшаяся часть вашего кода (например, основной цикл) просто должна периодически проверять, установлены ли какие-либо флаги.

Я думаю, что на самом деле неопределенное поведение если обработчик сигнала делает что-то кроме этого. Обновление: С man 2 signal: "См. signal(7) для получения списка функций, безопасных для асинхронных сигналов, которые можно безопасно вызывать из обработчика сигнала."

...