how to terminate a sleeping thread in pthread?

14,286

Solution 1

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.

Solution 2

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.

Share:
14,286
qiuxiafei
Author by

qiuxiafei

Little coder learning Clojure

Updated on July 08, 2022

Comments

  • qiuxiafei
    qiuxiafei almost 2 years

    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?

  • caf
    caf over 13 years
    Correct. This is the simple and non-racy way to do it.
  • R.. GitHub STOP HELPING ICE
    R.. GitHub STOP HELPING ICE about 13 years
    You can use pthread_cancel just fine without cleanup handlers, but if you've allocated resources that should be freed, doing so would result in a resource leak.
  • johnnycrash
    johnnycrash about 13 years
    I'm sure you are right when it comes to this subject. I had previously believed that cleanup_push and pop setup the longjump that pthread_cancel invoked. I guess you are you saying there is a default one setup by pthread_create. Do I have it right?
  • R.. GitHub STOP HELPING ICE
    R.. GitHub STOP HELPING ICE about 13 years
    At the end of the chain of cleanup handlers, the implementation-internal thread exit code (which includes thread-specific-data destructors and possibly other implementation-specific stuff) runs. If there are no cleanup handlers, execution passes directly there. Both cancellation and a call to pthread_exit by the thread itself have this effect.
  • R.. GitHub STOP HELPING ICE
    R.. GitHub STOP HELPING ICE about 13 years
    This is correct, but cancellation is easier and perhaps slightly more efficient. Of course if you call pthread_cancel on the thread, you need to make sure that it can't get cancelled at a point it shouldn't. Calling pthread_setcancelstate to disable cancellation when the thread starts, and only enabling it just before the sleep, would be a safe approach.
  • zeekvfu
    zeekvfu over 10 years
    IMO, pthread_cancel() may be preferable since sleep() is already a cancellation point. And be sure to call pthread_cleanup_push() and pthread_cleanup_pop() to set up cleanup handlers if you have allocated resources.
  • user1502776
    user1502776 almost 5 years
    What is the difference between using pthread_cond_timedwait with 1000ms timeout and using a flag variable with 100ms sleep in regard to race condition ?