Потоки и сигналы POSIX



Я пытался понять тонкости взаимодействия потоков POSIX и сигналов POSIX. В частности, меня интересует:




  • каков наилучший способ контролировать, в какой поток подается сигнал (предполагая, что он не является фатальным в первую очередь)?

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

  • как я могу безопасно обрабатывать передачу информации о том, что сигнал произошел с другими потоками? Это должно произойти в обработчике сигнала? (Я вообще не хочу убивать другие потоки; мне нужен гораздо более тонкий подход.)


Для справки о том, почему я хочу этого, я исследую как преобразовать TclX пакета для поддержки потоков, или разделить его и по крайней мере сделать некоторые полезные вспомогательные части темы. Сигналы являются одним из тех части, которые представляют особый интерес.

671   4  

4 ответов:

  • каков лучший способ контролировать, какой поток сигнал доставляется?

как указано в @zoli2k, явное назначение одного потока для обработки всех сигналов, которые вы хотите обработать (или набор потоков, каждый из которых имеет определенные обязанности по сигналу), является хорошим методом.

  • каков наилучший способ рассказать другой поток (который на самом деле может быть занят) что сигнал поступил?[...]
  • как я могу безопасно обрабатывать передачу информации о том, что сигнал произошел к другим нитям? Это должно произойти в обработчике сигнала?

я не буду говорить "лучше", но вот моя рекомендация:

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

самый простой способ сделать это-заставить поток принимать сигналы в цикле с помощью sigwaitinfo или sigtimedwait. Затем поток каким-то образом преобразует сигналы, возможно, транслируя a pthread_cond_t, пробуждение других потоков с большим количеством операций ввода-вывода, постановка команды в очередь потокобезопасных приложений, что угодно.

альтернативно, специальный поток смог позволить сигналам быть поставленным к обработчику сигнала, разоблачая для поставка только когда готово отрегулировать сигналы. (Доставка сигнала через обработчики, как правило, более подвержена ошибкам, чем прием сигнала через sigwait семья, однако.) В этом случае обработчик сигнала приемника выполняет некоторое простое и безопасное для асинхронного сигнала действие: setting sig_atomic_t флаги, называя sigaddset(&signals_i_have_seen_recently, latest_sig),write() байт для неблокирующего self-pipe и т. д. Затем, вернувшись в свой замаскированный основной цикл, поток передает прием сигнала другим потокам как выше.

(обновлено @caf справедливо указывает, что sigwait подходы превосходят.)

В соответствии со стандартом POSIX все потоки должны отображаться с одним и тем же PID в системе и использовать pthread_sigmask() вы можете определить маску блокировки сигнала для каждого потока.

поскольку разрешено определять только один обработчик сигнала на PID, я предпочитаю обрабатывать все сигналы в одном потоке и отправлять pthread_cancel() если запущенный поток должен быть отменен. Это предпочтительный способ против pthread_kill() так как он позволяет определить функции очистки для потоков.

на некоторых старых системы, из-за отсутствия надлежащей поддержки ядра, запущенные потоки могут иметь PID, отличный от PID родительского потока. См. FAQ для обработки сигналов с помощью linuxThreads на Linux 2.4.

IMHO, Unix V сигналы и posix потоки не смешиваются хорошо. Unix V-это 1970 год. POSIX-1980 ;)

есть точки отмены, и если вы разрешите сигналы и pthreads в одном приложении, вы в конечном итоге будете писать циклы вокруг каждого вызова, который может неожиданно вернуть EINTR.

Так что я сделал в (немногих) случаях, когда мне пришлось программировать многопоточность на Linux или QNX, чтобы замаскировать все сигналы для всех (кроме одного) потоков.

когда сигнал Unix V прибывает, процесс переключает стек (это было столько параллелизма в Unix V, сколько вы могли бы получить в процессе).

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

Как только вам удалось заставить поток обработчика сигнала работать, остается вопрос, как преобразовать информацию о сигнале в нечто цивилизованное, другие потоки могут использовать. Инфраструктура для межпотокового взаимодействия необходимых коммуникаций. Одним из полезных шаблонов является шаблон актора, где каждый из ваших потоков является целью для некоторого механизма обмена сообщениями в процессе.

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

где я нахожусь до сих пор:

  • сигналы поступают в разные основные классы, некоторые из которых, как правило, просто убивают процесс в любом случае (SIGILL), а некоторые из них никогда не нуждаются в чем-либо (SIGIO; проще просто сделать асинхронный IO в любом случае). Эти два класса не нуждаются в действии.
  • некоторые сигналы не нужно обрабатывать немедленно; подобные SIGWINCH могут быть поставлены в очередь до тех пор, пока это не будет удобно (так же, как событие из X11).
  • хитрые из них те, где вы хотите ответить на них, прервав то, что вы делаете, но не доходя до степени стирания нити. В частности, SIGINT в интерактивном режиме должен оставлять вещи отзывчивыми.

мне еще нужно разобраться signal vs sigaction,pselect,sigwait,sigaltstack, и целая куча других бит и кусков POSIX (и не POSIX) API.

Comments

    Ничего не найдено.