Спящий в потоке (Потоки C / POSIX) - PullRequest
12 голосов
/ 25 октября 2010

Я разрабатываю многопоточное приложение, которое использует POSIX Threads . Я использую потоки для выполнения периодического задания, и для этой цели я использую usleep (3) , чтобы приостановить выполнение потока. У меня вопрос, как я могу отменить таймер usleep () из основного потока, я попытался pthread_kill(thread, SIGALRM), но он имеет глобальный эффект, который приводит к завершению основного приложения (по умолчанию). Вот мой псевдокод:

void threaded_task(void *ptr) {
    initialize();

    while(running) {
        do_the_work();
        usleep(some_interval);
    }

    clean_up();
    release_resources();
}

А вот псевдо-функция, которая используется для остановки (и изящного отключения ) данного потока из основного потока :

void stop_thread(pthread_t thread) {
    set_running_state(thread, 0); // Actually I use mutex staff
    // TODO: Cancel sleep timer so that I will not wait for nothing.
    // Wait for task to finish possibly running work and clean up 
    pthread_join(thread, NULL);
}

Какой удобный способ достижения моей цели? Нужно ли использовать условные переменные или использовать варианты sleep ()?

Ответы [ 8 ]

9 голосов
/ 25 октября 2010

ИСПОЛЬЗУЙТЕ select() с FIFO или сокетом, который вы можете ткнуть, чтобы разбудить его.

6 голосов
/ 25 октября 2010

Вы также можете спать с семафором (на самом деле это их реальная цель).

a sema_wait в вашей теме и sema_post в вашей основной теме. Это легко, это чисто, это портативно. Вот ссылка на статью, подробно описывающую процедуру: http://www.netrino.com/node/202

5 голосов
/ 25 октября 2010

Причина, по которой SIGALRM убивает все приложение, заключается в том, что вы, вероятно, не зарегистрировали обработчик сигнала для него. Действие по умолчанию для SIGALRM состоит в том, чтобы ядро ​​завершило процесс, поэтому, если usleep реализован способом, который не использует SIGALRM (например, с использованием nanosleep или одной из функций опроса с тайм-аутом), тогда usleep не зарегистрировал бы обработчик или иным образом не изменил бы расположение сигнала по умолчанию.

void handle_alrm(int sig) {
}

...

int main(void) {
    signal(SIGALRM, handle_alrm);
    ...

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

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

4 голосов
/ 25 октября 2010

Мы используем ожидание переменной условия с таймаутом, используя pthread_cond_timedwait

Когда мы хотим завершить работу, мы устанавливаем переменную 'shutdown down' и делаем pthread_cond_broadcast

2 голосов
/ 13 января 2011

Может быть, вам нужно возиться с маской сигналов или, может быть, сигналы не могут выйти из спящего ... Я не знаю. Я не знаю, что может использовать sigwait () или sigtimedwait (). Мы используем pthread_kill, чтобы пробуждать потоки, но мы спим их, используя sigwait .... не usleep. Это самый быстрый способ, который я нашел, чтобы сделать это (в 40-50 раз быстрее, чем ожидание в pthread_cond согласно моим тестам.)

Мы делаем это перед созданием темы:

int fSigSet;
sigemptyset(&fSigSet);
sigaddset(&fSigSet, SIGUSR1);
sigaddset(&fSigSet, SIGSEGV);
pthread_sigmask(SIG_BLOCK, &fSigSet, NULL);

Каждая созданная нить наследует эту маску. Я немного путаюсь с масками. Вы либо говорите системе ничего не делать для определенных сигналов, либо, возможно, вы говорите системе, что обрабатываете некоторые сигналы ... Я не знаю. Кто-то другой может помочь нам. Если бы я лучше узнал, как работают маски, я мог бы сказать вам, что вы можете просто вставить приведенный выше код в ваш ThreadProc. Кроме того, я не уверен, нужен ли SIGSEGV.

Затем поток вызывает это, чтобы заснуть сам:

int fSigReceived;
// next line sleeps the thread
sigwait(&fSigSet, &fSigReceived);  // assuming you saved fSigSet from above...
// you get here when the thread is woken up by the signal
// you can check fSigReceived if you care what signal you got.

Затем вы делаете это, чтобы пробудить нить:

thread_kill(pThread, SIGUSR1);
2 голосов
/ 25 октября 2010

Есть несколько способов сделать это:

  • Использовать трюк с самоотводом @ упоминает Игнасио (Linux предоставляет удобный, но не переносимый, eventfd(2) для замены каналовздесь)
  • Соединение потоков через блокирующие очереди, построенные вокруг мьютексов и условных переменных, ожидание в пустой очереди, пробуждение элемента в очереди
  • Блокировка сигналов в главном потоке перед запуском других потоков , дождитесь сигнала, проснитесь по сигналу - см. pthread_sigmask(3)
2 голосов
/ 25 октября 2010

Похоже, вы работаете в Linux со справочной страницы. Вы должны быть в состоянии использовать nanosleep и перехватывать приложение, определенное (SIGRTMIN + x) для дочернего процесса. Nanosleep обладает функциональностью, которая должна прерываться сигналами и возвращать оставшееся время, которое он должен был спать. Вы также можете просто использовать сон, если вы используете более длительные периоды времени для сна.

nanosleep (2)

сигнал (7)

Любой упомянутый выше IPC также может помочь вам решить эту проблему.

РЕДАКТИРОВАТЬ: Похоже, вы уже делаете это, за исключением того, что вы должны использовать сигнал, который не будет иметь внешних последствий для программы. Любая из функций сна должна быть прервана неблокированным сигналом. Сигналы в реальном времени предназначены для использования в расчете на приложение.

2 голосов
/ 25 октября 2010

В качестве альтернативы select также возможно использование переменных условия pthread (см. pthread_cond_init, pthread_cond_wait и pthread_cond_signal), семафоров SysV или семафоров POSIX.Все они лучше подходят для потока обработки событий, чем usleep.

...