如何在pthread中终止睡眠线程?

时间:2011-01-24 03:32:54

标签: linux multithreading pthreads

我有线程睡了很长时间,然后醒来做某事,然后再次睡觉,这样:

while(some_condition)
{
    // do something
    sleep(1000);
}

我怎样才能让这个线程优雅而快速地退出?

我尝试使用pthread_cancel(),但无法取消睡眠线程。 我也试过改变while循环的条件,但是退出仍然需要很长时间。 而且我不想使用pthread_kill(),因为它可能会在线程工作时终止它。

那么,有什么好主意吗?

3 个答案:

答案 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_tpthread_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()函数。