как прервать спящий поток в pthread?
у меня есть нить, которая долго спит, потом просыпается, чтобы что-то сделать, потом снова спит, вот так:
while(some_condition)
{
// do something
sleep(1000);
}
как я могу сделать этот поток выход изящно и быстро?
Я пытался использовать pthread_cancel()
, но спящие потоки не могут быть отменены.
Я также попытался изменить состояние цикла while, но для выхода все равно потребуется много времени.
И я не хочу использовать pthread_kill()
, так как он может убить поток, когда он работает.
Итак, есть ли хорошие идеи?
3 ответов
в качестве альтернативы sleep
, вы могли бы использовать pthread_cond_timedwait с таймаутом 1000 мс. Затем, когда вы хотите выйти, сигнализируйте переменной условия.
это похоже на то, как вы могли бы сделать это в C#/Java, используя wait и notify.
классической переменной условия UNIX является self-pipe.
int fds[2];
pipe2(fds, O_NONBLOCK); // requires newish kernel and glibc; use pipe + 2*fcntl otherwise
child:
while (some_condition) {
// do something
struct pollfd pd = { .fd = fds[0], .events = POLLIN };
int rc;
char c;
while ((rc = poll(&pd, 1, 1000000)) == -1 && errno == EINTR)
// not entirely correct; 1000000 should be decreased according to elapsed time when repeating after a signal interruption
;
if (rc > 0 && (pd.revents & POLLIN) && read(fds[0], &c, 1) >= 0)
break;
}
parent:
cancel() {
char c = 0;
write(fds[1], &c, 1);
}
Да, это много неудобного (и непроверенного) кода. Вероятно, вы должны просто использовать pthread_cond_wait
требует pthread_mutex_t
и pthread_cond_t
но гораздо легче.
вы использовали pthread_cleanup_push и pop? Отмена с помощью pthread_cancel не работает без них. Вы должны использовать их в парах так же, как я сделал в примере ниже. если вы забудете один, он не будет компилироваться (причудливые макросы, один имеет " { " , а другой -"}"). Вы даже можете вложить различные уровни очистки / pops. Во всяком случае, они устанавливают точку прыжка в длину, которая отменяет прыжки, когда происходит отмена (довольно круто). Кроме того, если ваша тестовая программа не ждет запуска или остановки потока, вы может не заметить, что отмена происходит.
пример:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
static void *ThreadProc(void * arg);
static void unwind(__attribute__ ((unused)) void *arg);
int _fActive = 0;
int main(int argc, char** argv)
{
pthread_t Thread;
int nRet;
nRet = pthread_create(&Thread, NULL, ThreadProc, NULL);
printf("MAIN: waiting for thread to startup...\n");
while (_fActive == 0)
nanosleep(&(struct timespec){ 0, 0}, NULL);
printf("MAIN: sending cancel...\n");
nRet = pthread_cancel(Thread);
printf("MAIN: waiting for thread to exit...\n");
while (_fActive)
nanosleep(&(struct timespec){ 0, 0}, NULL);
printf("MAIN: done\n");
return 0;
}
static void unwind(__attribute__ ((unused)) void *arg)
{
// do some cleanup if u want
printf("THREAD: unwind (all threads, canceled or normal exit get here)\n");
_fActive = 0;
}
static void *ThreadProc(void * arg)
{
pthread_cleanup_push(unwind, arg);
// optional : pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
printf("THREAD: Enter Sleep\n");
_fActive = 1;
sleep(1000000);
printf("THREAD: Exit Sleep (canceled thread never gets here)\n");
pthread_cleanup_pop(1);
printf("THREAD: Exit (canceled thread never gets here)\n");
return NULL;
}
программа:
MAIN: waiting for thread to startup...
THREAD: Enter Sleep
MAIN: sending cancel...
MAIN: waiting for thread to exit...
THREAD: unwind (all threads, canceled or normal exit get here)
MAIN: done
обратите внимание, как отмена выходит из ThreadProc в точке отмены sleep () и выполняет только функцию unwind ().