我有线程睡了很长时间,然后醒来做某事,然后再次睡觉,这样:
while(some_condition)
{
// do something
sleep(1000);
}
我怎样才能让这个线程优雅而快速地退出?
我尝试使用pthread_cancel()
,但无法取消睡眠线程。
我也试过改变while循环的条件,但是退出仍然需要很长时间。
而且我不想使用pthread_kill()
,因为它可能会在线程工作时终止它。
那么,有什么好主意吗?
答案 0 :(得分:11)
作为sleep
的替代方案,您可以使用pthread_cond_timedwait超时1000毫秒。然后,当您想要退出时,发出条件变量信号。
这类似于使用wait和notify在C#/ Java中执行此操作的方法。
答案 1 :(得分:0)
经典的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
,但要容易得多。
答案 2 :(得分:0)
您使用过pthread_cleanup_push并弹出?没有它们,使用pthread_cancel取消是行不通的。您必须成对使用它们,就像我在下面的示例中所做的那样。如果你忘了一个它不会编译(花哨的宏,一个有'{'而另一个有'}')。您甚至可以嵌套不同级别的清理/弹出窗口。无论如何,他们设置了一个跳远点,取消跳转到取消发生时(非常酷)。此外,如果您的测试程序没有等待线程启动或停止,您可能不会注意到取消发生。
示例:
#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
请注意取消点sleep()中取消如何从ThreadProc中消失并仅执行unwind()函数。