Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to terminate a sleeping thread in pthread?

I have thread which sleeps for a long time, then wakes up to do something, then sleep again, like this:

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

How could I make this thread exit gracefully and QUICKLY?

I tried to use pthread_cancel(), but sleeping threads could not be canceled. I also tried changing the condition of the while loop, but it will still take long to exit. And I don't want to use pthread_kill(), since it may kill the thread when it's working.

So, are there any good ideas?

like image 938
qiuxiafei Avatar asked Jan 24 '11 03:01

qiuxiafei


People also ask

How do I stop sleeping thread?

interrupt() method: If any thread is in sleeping or waiting for a state then using the interrupt() method, we can interrupt the execution of that thread by showing InterruptedException. A thread that is in the sleeping or waiting state can be interrupted with the help of the interrupt() method of Thread class.

How do you kill a thread in Pthread?

The pthread_exit() function terminates the calling thread, making its exit status available to any waiting threads. Normally, a thread terminates by returning from the start routine that was specified in the pthread_create() call which started it.

What does Pthread cancel do?

DESCRIPTION top. The pthread_cancel() function sends a cancellation request to the thread thread. Whether and when the target thread reacts to the cancellation request depends on two attributes that are under the control of that thread: its cancelability state and type.

What happens to a thread when it sleeps?

Thread. sleep causes the current thread to suspend execution for a specified period. This is an efficient means of making processor time available to the other threads of an application or other applications that might be running on a computer system.


3 Answers

As an alternative to sleep, you could use pthread_cond_timedwait with a 1000 ms timeout. Then when you want to exit, signal the condition variable.

This is similar to how you might do this in C#/Java using wait and notify.

like image 71
karoberts Avatar answered Oct 13 '22 00:10

karoberts


The classic UNIX condition variable is the 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);
    }

Yeah, it's a lot of fiddly (and untested) code. You should probably just use pthread_cond_wait, it requires a pthread_mutex_t and a pthread_cond_t but is much easier.

like image 44
ephemient Avatar answered Oct 12 '22 22:10

ephemient


Did you use pthread_cleanup_push and pop? Canceling with pthread_cancel doesn't work without them. You must use them in pairs just like I did in the example below. if you forget one it wont compile (fancy macros, one has the '{' and the other has the '}'). You can even nest different levels of cleanup/pops. Anyway, they set a long jump point that cancel jumps to when cancel occurs (pretty cool). Also, if your test program does not wait for the thread to start or to stop, you may not notice the canceling happening.

Example:

#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;
}

Program output:

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

Notice how the cancel blows out of ThreadProc at the cancel point sleep() and executes only the unwind() function.

like image 36
johnnycrash Avatar answered Oct 13 '22 00:10

johnnycrash