sigprocmask во время выполнения сигнала
Я в настоящее время исследую с помощью 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 ответа
Имейте в виду, что поведение по умолчанию внутри обработчика сигнала заключается в блокировке обрабатываемого сигнала. Также при выполнении вызовов функций внутри обработчиков сигналов требуется вызывать только безопасные функции. С этим сказал, sigprocmask()
является функцией, безопасной для сигнала, и если вы используете ее для блокировки того же сигнала, который блокируется обработчиком сигнала, который вызывается внутри, то на самом деле ничего не произойдет... вы останетесь с тем же сигнальная маска, которая у вас есть на данный момент. Разница лишь в том, что внутри обработчика сигналов только сигналы для SIGALRM
или же SIGCHLD
гарантированно будут заблокированы (это будет зависеть от того, в каком обработчике сигналов вы находитесь), где-как при вызове sigprocmask()
чтобы заблокировать эти конкретные сигналы, оба сигнала будут заблокированы после вызова.
Остерегайтесь второй части вашего кода в criticalFunction
когда ты пытаешься позвонить sigprocmask()
включить сигналы, которые в данный момент заблокированы в маске сигналов. Это может создать ситуацию, когда вы в конечном итоге получаете уровень повторного входа в вызовы вашего обработчика сигнала. Другими словами, включение сигнала для обработчика сигнала, в котором вы находитесь, может означать, что перед выходом из текущего обработчика сигнала, другой SIGALRM
или же SIGCHLD
перехвачен, и вы снова войдете в обработчик сигнала, чтобы обработать этот вновь перехваченный сигнал. Пока вы активируете сигналы после каких-либо критических обновлений, я думаю, что вы будете в порядке с этой повторяющейся ситуацией, но просто для того, чтобы избежать опасностей, вы можете включить сигналы только в criticalFunction
в самом конце criticalFunction
не где-то посередине, а когда вернешься из criticalFunction
, не делайте ничего, что не было бы асинхронно безопасным... вы должны предположить, что любой код после возвращения второго sigprocmask()
может выполняться не по порядку (т. е. может выполняться после того, как второй сигнал был перехвачен и его обработчик сигнала был запущен).
Вы должны были бы беспокоиться о "остановке", если бы попытались позвонить с exec
семья, или что-то в этом роде внутри вашего обработчика сигналов. Что произойдет, так это то, что вновь наложенный процесс унаследует маску сигналов от текущего процесса, поэтому, если текущий процесс заблокировал определенные сигналы, они также будут заблокированы в новом процессе. Таким образом, если новый процесс предполагал, что сигналы были разблокированы, ваш обработчик сигналов в новом процессе никогда не будет работать.
Кстати, одно предупреждение: не смешивайте сигналы и потоки! Вы упоминаете "основной процесс" в своем вопросе... Надеюсь, это не значит, что вы пытаетесь смешивать сигналы и потоки. Если это так, то для этого требуется очень специфическая идиома, в противном случае вы создадите разного рода хаос.
Ваш дизайн неправильный, когда вы говорите, что "обработчики сигналов [...] вызывают criticalFunction
"Обработчики сигналов никогда не должны выполнять какую-либо серьезную работу. Они не созданы для этого.
Единственное, что вы должны разумно сделать из обработчика сигнала, это изменить переменную типа sigatomic_t
, Это обычно используется для установки флага, а оставшаяся часть вашего кода (например, основной цикл) просто должна периодически проверять, установлены ли какие-либо флаги.
Я думаю, что это на самом деле неопределенное поведение, если обработчик сигнала делает что-то другое. Обновление: с man 2 signal
: "Увидеть signal(7)
список асинхронно-безопасных функций, которые можно безопасно вызывать из обработчика сигнала."