основные / рабочие потоки и обработка сигналов - PullRequest
6 голосов
/ 27 мая 2009

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

Главный поток запускается и выполняет все распределение

Главный поток устанавливает обработчик сигнала SIGINT

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

Когда SIGINT получен, я понимаю, что только один поток получает его. Так что, если поток спит по системному вызову или семафору, они не проснутся, и я не смогу pthread_join в моих рабочих потоках и выполните всю необходимую очистку в моем основном потоке.

Может ли следующий обработчик сигнала решить мою проблему?

void term(int sig)
{
    g_do_cleanup = 1;
    pthread_kill(worker_1_id, some_other_signal);
    ...
    pthread_kill(worker_2_id, some_other_signal);
}

Я ожидаю, что после получения SIGINT все потоки будут оповещены другим сигналом, выйдут из своего блокирующего вызова, увидят флаг g_do_cleanup и изящно выйдут.

Любые комментарии или ссылки о том, как это сделать правильно, приветствуются.

Редактировать: Я НЕ ищу способ пробуждения многопотокового ожидания в определенном состоянии, поэтому я не думаю, что подход pthread_cond_signal - это то, что я ищу. То, что я хочу, это:

  • Найдите способ, которым все темы, которые заблокирован на блокирующем вызове возвращается от этих звонков.
  • Или убить все темы, кроме основной.

Ответы [ 3 ]

4 голосов
/ 28 мая 2009

Это то, что я обычно делаю в основной ветке приложения:


/* before starting other threads */
sigset_t sigs;
sigemptyset( &sigs );
sigaddset( &sigs, SIGTERM );
sigaddset( &sigs, SIGINT );
/* add other signals to handle */
if ( pthread_sigmask( SIG_BLOCK, &sigs, 0 )) { /* handle error */ }
/* can start threads now */
...
/* in the main event loop */
siginfo_t info;
if ( sigwaitinfo( &sigs, &info ) == -1 ) { /* handle error */ }
switch( info.si_signo )
{
  case SIGTERM:
  case SIGINT: /* raise shutdown event */ break;
  default: /* other actions - log rotation, etc. */
}
...

Таким образом, сигналы становятся обычными событиями приложения - без особых ограничений контекста сигнала и т. Д. Ожидание также можно выполнить с таймаутом через sigtimedwait, хотя производные BSD его не поддерживают.

2 голосов
/ 27 мая 2009

Мне кажется, что вы хотите переменную условия pthread, так что вы можете разбудить любое количество нескольких потоков, выделив одно «событие» из вашего основного потока.

Для получения дополнительной информации см. Справочные страницы для PTHREAD_COND_DESTROY и PTHREAD_COND_BROADCAST .

1 голос
/ 28 мая 2009

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

Я думаю, что я бы пошел с отдельным потоком для обработки сигнала процесса, а не мастера. Пусть он будет ждать вечно на семафоре или sigwait () или на чем угодно, ожидая запуска обработчика сигнала Переместите код pthread-kill из обработчика сигнала. Просто установите переключатель, и поток ожидания сигнала отправит other_signal рабочим потокам и выйдет сам.

...