Сигнализация всех потоков в процессе

Не сохраняя список текущих потоков, я пытаюсь увидеть, что сигнал в реальном времени доставляется всем потокам в моем процессе. Моя идея состоит в следующем:

  • Изначально установлен обработчик сигнала, и сигнал разблокирован во всех потоках.
  • Когда один поток хочет отправить «широковещательный» сигнал, он получает мьютекс и устанавливает глобальный флаг того, что широковещательная передача имеет место.
  • Отправитель блокирует сигнал (используя pthread_sigmask ) для себя и входит в цикл, многократно вызывая raise (sig) , пока sigpending не указывает, что сигнал в ожидании (не осталось потоков с заблокированным сигналом).
  • Когда потоки получают сигнал, они воздействуют на него, но ожидают в обработчике сигнала сброса флага широковещательной передачи, чтобы сигнал оставался замаскированным.
  • Отправитель завершает цикл, разблокировав сигнал (для получения собственной доставки).
  • Когда отправитель обрабатывает свой собственный сигнал, он сбрасывает глобальный флаг, чтобы все другие потоки могли продолжить свои дела.

Проблема, с которой я столкнулся, заключается в том, что pthread_sigmask не соблюдается. Все работает правильно, если я запускаю тестовую программу под strace (предположительно из-за другого времени планирования), но как только я запускаю ее в одиночку, отправитель получает свой собственный сигнал (несмотря на то, что заблокировал его ..?) и ни один из других потоков никогда не планируется.

Есть идеи, что может быть не так? Я пробовал использовать sigqueue вместо raise , проверяя маску сигнала, добавляя повсюду sleep , чтобы убедиться, что потоки терпеливо ждут своих сигналов. и т. д. и теперь я в растерянности.

Изменить: Благодаря ответу psmears, я думаю, что понимаю проблему. Вот возможное решение.Обратная связь была бы отличной:

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

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

Редактировать 2: ] Кажется, сейчас он работает. Согласно документации для sigqueue , он возвращает EAGAIN , если ему не удается поставить сигнал в очередь. Но для надежности я решил просто продолжать вызывать sigqueue до тех пор, пока не запустятся обработчики сигналов num_threads-1 , чередуя вызовы к sched_yield после того, как я отправил num_threads-1 сигналов.

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

9
задан R.. 18 November 2010 в 08:35
поделиться