Доставка сигналов только одному потоку : может ли часть потеряться?

Доставка сигналов только одному потоку : может ли часть потеряться?

06.12.2012 03:32:45 Просмотров 17 Источник

Всем добрый день!
Если доставка некоторого сигнала разрешена только одному из потоков, может ли на практике быть случай, когда несколько однотипных сигналов (SIGCHLD) будут посланы практически одновременно, и процессор не успеет переключиться на данный поток вовремя, вследствии чего обработчик сигнала выполнится 1 раз вместо, к примеру, 3-х ?

У вопроса есть решение - Посмотреть?

https://ru.stackoverflow.com/questions/171074/%d0%94%d0%be%d1%81%d1%82%d0%b0%d0%b2%d0%ba%d0%b0-%d1%81%d0%b8%d0%b3%d0%bd%d0%b0%d0%bb%d0%be%d0%b2-%d1%82%d0%be%d0%bb%d1%8c%d0%ba%d0%be-%d0%be%d0%b4%d0%bd%d0%be%d0%bc%d1%83-%d0%bf%d0%be%d1%82%d0%be%d0%ba%d1%83-%d0%bc%d0%be%d0%b6%d0%b5%d1%82-%d0%bb%d0%b8-%d1%87%d0%b0%d1%81%d1%82%d1%8c-%d0%bf%d0%be%d1%82%d0%b5%d1%80%d1%8f%d1%82%d1%8c%d1%81%d1%8f#comment171088_171074
хм, а если первый обработчик завершит процесс?
https://ru.stackoverflow.com/questions/171074/%d0%94%d0%be%d1%81%d1%82%d0%b0%d0%b2%d0%ba%d0%b0-%d1%81%d0%b8%d0%b3%d0%bd%d0%b0%d0%bb%d0%be%d0%b2-%d1%82%d0%be%d0%bb%d1%8c%d0%ba%d0%be-%d0%be%d0%b4%d0%bd%d0%be%d0%bc%d1%83-%d0%bf%d0%be%d1%82%d0%be%d0%ba%d1%83-%d0%bc%d0%be%d0%b6%d0%b5%d1%82-%d0%bb%d0%b8-%d1%87%d0%b0%d1%81%d1%82%d1%8c-%d0%bf%d0%be%d1%82%d0%b5%d1%80%d1%8f%d1%82%d1%8c%d1%81%d1%8f#comment171092_171074
ну если процесс после будет завершаться, то вобщем-то все равно. но тут в первую очередь о SIGCHLD, т.е. можно ли таким образом потерять обработку завершения одного из дочерних процессов?

Ответы - Доставка сигналов только одному потоку : может ли часть потеряться? / Доставка сигналов только одному потоку : может ли часть потеряться?

akalend

06.12.2012 03:44:23

Не путаем понятия потоки (threads) и процессы (process).
Процесс может содержать в себе несколько потоков (тредов или нитей).

Если используешь сигналы, то он направляется конкретно процессу, а значит обработчику сигнала в этом процессе.

https://ru.stackoverflow.com/questions/171074/%d0%94%d0%be%d1%81%d1%82%d0%b0%d0%b2%d0%ba%d0%b0-%d1%81%d0%b8%d0%b3%d0%bd%d0%b0%d0%bb%d0%be%d0%b2-%d1%82%d0%be%d0%bb%d1%8c%d0%ba%d0%be-%d0%be%d0%b4%d0%bd%d0%be%d0%bc%d1%83-%d0%bf%d0%be%d1%82%d0%be%d0%ba%d1%83-%d0%bc%d0%be%d0%b6%d0%b5%d1%82-%d0%bb%d0%b8-%d1%87%d0%b0%d1%81%d1%82%d1%8c-%d0%bf%d0%be%d1%82%d0%b5%d1%80%d1%8f%d1%82%d1%8c%d1%81%d1%8f/171084#comment171087_171084
@akalend, гениально... :) Вы вопрос читали? Он про обработку сигналов в многопоточной программе.
avp

06.12.2012 03:58:32

Может.

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

Является ответом!
VladD

06.12.2012 04:00:50

Да, есть проблема. Если несколько сигналов SIGCHLD одновременно ждут доставки, будет доставлен лишь один сигнал. Источник. Там же рекомендация по обходу проблемы.


Вот ещё, судя по всему, полезная информация по теме: handling SIGCHLD with multiple children.

https://ru.stackoverflow.com/questions/171074/%d0%94%d0%be%d1%81%d1%82%d0%b0%d0%b2%d0%ba%d0%b0-%d1%81%d0%b8%d0%b3%d0%bd%d0%b0%d0%bb%d0%be%d0%b2-%d1%82%d0%be%d0%bb%d1%8c%d0%ba%d0%be-%d0%be%d0%b4%d0%bd%d0%be%d0%bc%d1%83-%d0%bf%d0%be%d1%82%d0%be%d0%ba%d1%83-%d0%bc%d0%be%d0%b6%d0%b5%d1%82-%d0%bb%d0%b8-%d1%87%d0%b0%d1%81%d1%82%d1%8c-%d0%bf%d0%be%d1%82%d0%b5%d1%80%d1%8f%d1%82%d1%8c%d1%81%d1%8f/171101#comment171105_171101
угу, я так и делаю. Я правда пока что такой ситуации смоделировать не смогла, и при завершении 5 потомков все их ресурсы освобождаются при вызове первого обработчика, а дальше 4 обработчика срабатывают вхолостую, обидно как то...
https://ru.stackoverflow.com/questions/171074/%d0%94%d0%be%d1%81%d1%82%d0%b0%d0%b2%d0%ba%d0%b0-%d1%81%d0%b8%d0%b3%d0%bd%d0%b0%d0%bb%d0%be%d0%b2-%d1%82%d0%be%d0%bb%d1%8c%d0%ba%d0%be-%d0%be%d0%b4%d0%bd%d0%be%d0%bc%d1%83-%d0%bf%d0%be%d1%82%d0%be%d0%ba%d1%83-%d0%bc%d0%be%d0%b6%d0%b5%d1%82-%d0%bb%d0%b8-%d1%87%d0%b0%d1%81%d1%82%d1%8c-%d0%bf%d0%be%d1%82%d0%b5%d1%80%d1%8f%d1%82%d1%8c%d1%81%d1%8f/171101#comment171121_171101
@margosh, а у Вас что, они (обработчики) в разных потоках вызываются?
https://ru.stackoverflow.com/questions/171074/%d0%94%d0%be%d1%81%d1%82%d0%b0%d0%b2%d0%ba%d0%b0-%d1%81%d0%b8%d0%b3%d0%bd%d0%b0%d0%bb%d0%be%d0%b2-%d1%82%d0%be%d0%bb%d1%8c%d0%ba%d0%be-%d0%be%d0%b4%d0%bd%d0%be%d0%bc%d1%83-%d0%bf%d0%be%d1%82%d0%be%d0%ba%d1%83-%d0%bc%d0%be%d0%b6%d0%b5%d1%82-%d0%bb%d0%b8-%d1%87%d0%b0%d1%81%d1%82%d1%8c-%d0%bf%d0%be%d1%82%d0%b5%d1%80%d1%8f%d1%82%d1%8c%d1%81%d1%8f/171101#comment171417_171101
@avp, напротив, только в одном. В остальных получение SIGCHLD заблокировано.
https://ru.stackoverflow.com/questions/171074/%d0%94%d0%be%d1%81%d1%82%d0%b0%d0%b2%d0%ba%d0%b0-%d1%81%d0%b8%d0%b3%d0%bd%d0%b0%d0%bb%d0%be%d0%b2-%d1%82%d0%be%d0%bb%d1%8c%d0%ba%d0%be-%d0%be%d0%b4%d0%bd%d0%be%d0%bc%d1%83-%d0%bf%d0%be%d1%82%d0%be%d0%ba%d1%83-%d0%bc%d0%be%d0%b6%d0%b5%d1%82-%d0%bb%d0%b8-%d1%87%d0%b0%d1%81%d1%82%d1%8c-%d0%bf%d0%be%d1%82%d0%b5%d1%80%d1%8f%d1%82%d1%8c%d1%81%d1%8f/171101#comment171421_171101
Тогда я не понимаю, откуда берутся 4 "холостых". По идее может быть только один. Или у Вас SA_NODEFER в sigaction sa_flags установлен? SA_NODEFER If this bit is set, further occurrences of the delivered signal are not masked during the execution of the handler. Это цитата из FreeBSD man sigaction. Насколько я понимаю, установка этого бита разрешает "рекурсивный" вызов обработчика. В кавычках, посколько это не совсем рекурсия, ведь не сам же обработчик себя вызывает.
https://ru.stackoverflow.com/questions/171074/%d0%94%d0%be%d1%81%d1%82%d0%b0%d0%b2%d0%ba%d0%b0-%d1%81%d0%b8%d0%b3%d0%bd%d0%b0%d0%bb%d0%be%d0%b2-%d1%82%d0%be%d0%bb%d1%8c%d0%ba%d0%be-%d0%be%d0%b4%d0%bd%d0%be%d0%bc%d1%83-%d0%bf%d0%be%d1%82%d0%be%d0%ba%d1%83-%d0%bc%d0%be%d0%b6%d0%b5%d1%82-%d0%bb%d0%b8-%d1%87%d0%b0%d1%81%d1%82%d1%8c-%d0%bf%d0%be%d1%82%d0%b5%d1%80%d1%8f%d1%82%d1%8c%d1%81%d1%8f/171101#comment171424_171101
завершаются 5 порожденных процессов, посылаются 5 сигналов, их обработчик просто пишет в пайп признак, что дочерний завершен. В другом потоке пайп проверяется, и если там есть этот признак, вызывается waitpid() в цикле, пока не вернет отсутствие дочерних. Затем снова проверяется пайп, а там - еще 4 признака... ранее я вызывала waitpid() по одному на признак, но теперь думаю, что если процессор вовремя не переключится на тот поток, где получение сигналов разрешено, то их туда прийдет больше одного, а признак в пайп запишется только 1.
https://ru.stackoverflow.com/questions/171074/%d0%94%d0%be%d1%81%d1%82%d0%b0%d0%b2%d0%ba%d0%b0-%d1%81%d0%b8%d0%b3%d0%bd%d0%b0%d0%bb%d0%be%d0%b2-%d1%82%d0%be%d0%bb%d1%8c%d0%ba%d0%be-%d0%be%d0%b4%d0%bd%d0%be%d0%bc%d1%83-%d0%bf%d0%be%d1%82%d0%be%d0%ba%d1%83-%d0%bc%d0%be%d0%b6%d0%b5%d1%82-%d0%bb%d0%b8-%d1%87%d0%b0%d1%81%d1%82%d1%8c-%d0%bf%d0%be%d1%82%d0%b5%d1%80%d1%8f%d1%82%d1%8c%d1%81%d1%8f/171101#comment171427_171101
Тогда все ясно и все нормально. Сигналы приходят раздельно. Все 5 обрабатываются. -- Если не хотите лишний раз вызывать waitpid, то можно попробовать запоминать сколько раз waitpid уже сработал и просто игнорировать лишние требования, читаемые из пайпа. Но (запрограммированный "в лоб") этот подход не будет работать, если сигнал "потеряется" (скажем 3 процесса завершатся "одновременно" и обработчик вызовется 2 раза). Некоторое время будут болтаться зомби. Ну, тут можно учесть время от последнего чтения пайпа (или что-то в этом духе). Поэтому на практике лучше не усложнять.
https://ru.stackoverflow.com/questions/171074/%d0%94%d0%be%d1%81%d1%82%d0%b0%d0%b2%d0%ba%d0%b0-%d1%81%d0%b8%d0%b3%d0%bd%d0%b0%d0%bb%d0%be%d0%b2-%d1%82%d0%be%d0%bb%d1%8c%d0%ba%d0%be-%d0%be%d0%b4%d0%bd%d0%be%d0%bc%d1%83-%d0%bf%d0%be%d1%82%d0%be%d0%ba%d1%83-%d0%bc%d0%be%d0%b6%d0%b5%d1%82-%d0%bb%d0%b8-%d1%87%d0%b0%d1%81%d1%82%d1%8c-%d0%bf%d0%be%d1%82%d0%b5%d1%80%d1%8f%d1%82%d1%8c%d1%81%d1%8f/171101#comment171431_171101
угу. если бы в пайп, как Вы уже когда-то предлагали, вместо признака кидать pid завершенного дочернего, вызвав waitpid() в обработчике, то этих допвызовов действительно бы не было, однако у меня в тот же пайп кидаются еще признаки завершения потоков, и признак прихода SIGTERM. Не знаю, вполне ли это корректно, но после предшествующих обсуждений постаралась свести к минимуму действия в обработчиках сигналов. Теоретически, можно вместо остальных признаков бросать в пайп pids, которые точно не могут быть потомками, 0 например, и принимать это за признак завершения потока, как считаете?
https://ru.stackoverflow.com/questions/171074/%d0%94%d0%be%d1%81%d1%82%d0%b0%d0%b2%d0%ba%d0%b0-%d1%81%d0%b8%d0%b3%d0%bd%d0%b0%d0%bb%d0%be%d0%b2-%d1%82%d0%be%d0%bb%d1%8c%d0%ba%d0%be-%d0%be%d0%b4%d0%bd%d0%be%d0%bc%d1%83-%d0%bf%d0%be%d1%82%d0%be%d0%ba%d1%83-%d0%bc%d0%be%d0%b6%d0%b5%d1%82-%d0%bb%d0%b8-%d1%87%d0%b0%d1%81%d1%82%d1%8c-%d0%bf%d0%be%d1%82%d0%b5%d1%80%d1%8f%d1%82%d1%8c%d1%81%d1%8f/171101#comment171449_171101
@margosh, не думаю, что несколько лишних waitpid катастрофически замедлят программу. Я уже точно не помню все детали, но мне кажется речь шла о потоке (том что читает пайп), который пишет лог и может быть делает какое-то управление. Поэтому я и предлагал посылать ему pid (естественно, полученный где-то (видимо в обработчике) из waitpid) и не предполагал, что он будет сам waitpid вызывать. А все записи в пайп лучше оформить как команды с расписанными форматами. Тогда эту штуку будет легко развивать. Предпочтителен фиксированный размер таких команд (проще программировать).
Закрыть X