как прекратить спящий поток в pthread? - PullRequest
8 голосов
/ 24 января 2011

У меня есть нить, которая долго спит, затем просыпается, чтобы что-то сделать, затем снова спит, вот так:

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

Как я могу сделать так, чтобы этот поток вышел изящно и БЫСТРО?

Я пытался использовать pthread_cancel(), но спящие потоки не могли быть отменены. Я также попытался изменить условие цикла while, но для выхода все равно потребуется много времени. И я не хочу использовать pthread_kill(), так как он может убить поток, когда он работает.

Итак, есть ли хорошие идеи?

Ответы [ 3 ]

11 голосов
/ 24 января 2011

В качестве альтернативы sleep вы можете использовать pthread_cond_timedwait с тайм-аутом 1000 мс.Затем, когда вы хотите выйти, подайте сигнал условной переменной.

Это похоже на то, как вы можете сделать это в C # / Java, используя wait и notify.

0 голосов
/ 25 января 2011

Вы использовали pthread_cleanup_push и pop?Отмена с помощью 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

Обратите внимание, как отмена выдувается из ThreadProc в точке отмены sleep () и выполняет только функцию unwind ().

0 голосов
/ 24 января 2011

Классическая переменная условия 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, но это намного проще.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...