Спящий в потоке (потоки C / POSIX)
Я разрабатываю многопоточное приложение, которое использует потоки POSIX. Я использую потоки для выполнения издание работа и для этой цели я использую 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 ответов
вы также можете спать с семафором (это на самом деле их настоящая цель).
a sema_wait
в вашем потоке и sema_post
в основном потоке. Это легко, это чисто, это портативный. Здесь ссылка на статью, подробно описывающую процедуру:
http://www.netrino.com/node/202
причина, по которой SIGALRM убивает все приложение, заключается в том, что вы, вероятно, не зарегистрировали обработчик сигнала для него. Действие по умолчанию для SIGALRM заключается в завершении процесса ядром, поэтому если usleep
реализуется способом, который не использует SIGALRM (используя nanosleep
или одна из функций опроса с таймаутом, например), то usleep
не зарегистрировал бы обработчик или иным образом изменил бы расположение по умолчанию сигнал.
void handle_alrm(int sig) {
}
...
int main(void) {
signal(SIGALRM, handle_alrm);
...
должно быть достаточно, чтобы не убить вашу программу, хотя вы должны посмотреть на более сложные
мы используем ожидание переменной условия с таймаутом, используя pthread_cond_timedwait
когда мы хотим завершить работу, мы устанавливаем переменную "shuting down" и делаем pthread_cond_broadcast
в качестве альтернативы select
, также можно использовать переменные условия pthread (см. pthread_cond_init
, pthread_cond_wait
и pthread_cond_signal
), семафоры SysV или семафоры POSIX. Все это лучше подходит, чем usleep для потока обработки событий.
похоже, что вы работаете в Linux с указанной справочной страницы. Вы должны иметь возможность использовать nanosleep и interupt с определенным приложением (SIGRTMIN+x) для дочернего процесса. Nanosleep имеет функциональность, которая должна быть прервана сигналами и вернуть оставшееся время, которое он должен был спать. Вы также можете просто использовать сон, Если используете большие периоды времени для спать.
любой вид IPC, упомянутый выше, также может помочь вам решить эту проблему.
EDIT: похоже, вы уже делаете это, за исключением того, что вы должны использовать сигнал, который не будет иметь внешних эффектов на программу. Любую из функций сна должна быть прервана не блокировали сигнал. Сигналы в реальном времени предназначены для использования в каждом приложении основа.
есть несколько способов сделать это:
- используйте self-pipe trick @Ignacio упоминает (Linux предоставляет удобный, но не портативный,
eventfd(2)
заменить трубы здесь) - подключение потоков через блокирующие очереди, построенные вокруг мьютексов и условных переменных, ожидание пустой очереди, пробуждение элемента в очереди
- блокировать сигналы в основной поток перед запуском других потоков, ждать сигнала, пробуждение по сигналу-см.
pthread_sigmask(3)
Возможно, вам нужно возиться с маской сигнала или, возможно, сигналы не могут выйти из usleep...Я не знаю. Я не знаю, что может использовать sigwait () или sigtimedwait (). Мы используем pthread_kill для пробуждения потоков, но мы спим их с помощью sigwait....не usleep. Это самый быстрый способ, который я нашел, чтобы разбудить это (40-50x быстрее, чем ожидание на 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);