- Как лучше всего контролировать, в какой поток доставляется сигнал?
Как указано в @ zoli2k, явное назначение одного потока для обработки всех сигналов, которые вы хотите обработать (или набора потоков, каждый из которых имеет определенные обязанности по сигналу), является хорошим методом.
- Как лучше всего сообщить другому потоку (который действительно может быть занят), что сигнал прибыл? [...]
- Как я могу безопасно обрабатывать передачу информации о том, что сигнал поступил в другие потоки? Должно ли это происходить в обработчике сигналов?
Я не буду говорить «лучше всего», но вот моя рекомендация:
Заблокируйте все желаемые сигналы main
, чтобы все потоки унаследовали эту сигнальную маску. Затем модифицируйте поток приема специального сигнала как управляемый сигналами цикл событий, отправляя вновь поступившие сигналы в качестве некоторой другой связи внутри потока .
Самый простой способ сделать это - заставить поток принимать сигналы в цикле с помощью sigwaitinfo
илиsigtimedwait
. Затем поток каким-то образом преобразует сигналы, возможно, транслируя pthread_cond_t
, пробуждая другие потоки с большим количеством операций ввода-вывода, помещая команду в очередь, ориентированную на конкретное приложение, потокобезопасную, что угодно.
В качестве альтернативы, специальный поток может позволять доставлять сигналы обработчику сигналов, демаскируя их для доставки только тогда, когда они готовы обработать сигналы. (Однако доставка сигнала через обработчики обычно более подвержена ошибкам, чем прием сигнала через sigwait
семейство.) В этом случае обработчик сигнала получателя выполняет некоторые простые и безопасные для асинхронного сигнала действия: установка sig_atomic_t
флагов, вызов sigaddset(&signals_i_have_seen_recently, latest_sig)
, write
() байта к неблокирующему собственному каналу и т. д. Затем, вернувшись в свой замаскированный основной цикл, поток сообщает о получении сигнала другим потокам, как указано выше.
( ОБНОВЛЕНИЕ @caf справедливо указывает на sigwait
превосходство подходов.)
sigwaitinfo()
(илиsigtimedwait()
), а затем отправляет их остальной части приложения, как описано в последнем абзаце.В соответствии со стандартом POSIX все потоки должны появляться в системе с одним и тем же PID, и с помощью
pthread_sigmask()
вы можете определить маску блокировки сигнала для каждого потока.Поскольку разрешено определять только один обработчик сигналов для каждого PID, я предпочитаю обрабатывать все сигналы в одном потоке и отправлять,
pthread_cancel()
если работающий поток необходимо отменить. Это предпочтительный способ,pthread_kill()
поскольку он позволяет определять функции очистки для потоков.В некоторых старых системах из-за отсутствия надлежащей поддержки ядра запущенные потоки могут иметь PID, отличный от PID родительского потока. См. FAQ по обработке сигналов с помощью linuxThreads в Linux 2.4 .
источник
make menuconfig
со свежеклонированной веткой git master uClibc. Там является выбор между старым LinuxThreads и новой NPTL как реализации резьбы по стандарту POSIX, но помощи от года 2012 по- прежнему рекомендует против выбора NPTL. Таким образом, в современных встроенных системах Linux до сих пор часто встречается устаревшая реализация LinuxThreads, даже если в системе используется достаточно новое ядро Linux.Где я сейчас:
У меня еще есть перебирать
signal
противsigaction
,pselect
,sigwait
,sigaltstack
, и целая куча других кусочков POSIX (и не-POSIX) API.источник
IMHO, сигналы Unix V и потоки posix плохо сочетаются. Unix V - 1970. POSIX - 1980;)
Есть точки отмены, и если вы разрешите сигналы и потоки в одном приложении, вы в конечном итоге будете писать циклы вокруг каждого вызова, которые могут неожиданно возвращать EINTR.
Итак, что я делал в (нескольких) случаях, когда мне приходилось программировать многопоточность в Linux или QNX, так это замаскировать все сигналы для всех (кроме одного) потоков.
Когда поступает сигнал Unix V, процесс переключает стек (в Unix V это было столько параллелизма, сколько вы могли получить внутри процесса).
Как намекают другие сообщения здесь, теперь можно было бы сообщить Системе, какой поток posix должен стать жертвой этого переключения стека.
Как только вам удалось запустить поток обработчика сигналов, остается вопрос, как преобразовать информацию о сигнале во что-то цивилизованное, которое могут использовать другие потоки. Требуется инфраструктура для межпотокового взаимодействия. Один из полезных шаблонов - это шаблон актора, в котором каждый из ваших потоков является целью для некоторого внутрипроцессного механизма обмена сообщениями.
Итак, вместо того, чтобы отменять другие потоки или убивать их (или другие странные вещи), вы должны попытаться маршалировать сигнал из контекста сигнала в поток обработчика сигнала, а затем использовать механизмы взаимодействия с шаблоном актора для отправки семантически полезных сообщений этим субъектам, кому нужна информация, связанная с сигналом.
источник