Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how the child POSIX thread is canceled

// threadA.c
int main() {
    int res;
    pthread_t a_thread;
    void *thread_result;

    res = pthread_create(&a_thread, NULL, thread_function, NULL);
    if (res != 0) {
        perror("Thread creation failed");
        exit(EXIT_FAILURE);
    }
    sleep(3);
    printf("Canceling thread...\n");
    res = pthread_cancel(a_thread);
    if (res != 0) {
        perror("Thread cancelation failed");
        exit(EXIT_FAILURE);
    }
    printf("Waiting for thread to finish...\n");
    res = pthread_join(a_thread, &thread_result);
    if (res != 0) {
        perror("Thread join failed");
        exit(EXIT_FAILURE);
    }
    exit(EXIT_SUCCESS);
}

void *thread_function(void *arg) {
    int i, res, j;
    res = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
    if (res != 0) {
        perror("Thread pthread_setcancelstate failed");
        exit(EXIT_FAILURE);
    }
    res = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
    if (res != 0) {
        perror("Thread pthread_setcanceltype failed");
        exit(EXIT_FAILURE);
    }
    printf("thread_function is running\n");
    for(i = 0; i < 10; i++) {
        printf("Thread is still running (%d)...\n", i);
        sleep(1);
    }
    pthread_exit(0);
}

Output is as follows:

$ ./threadA
thread_function is running
Thread is still running (0)...
Thread is still running (1)...
Thread is still running (2)...
Canceling thread...
Waiting for thread to finish...
$

When finishing waiting 3 seconds, the main thread issues the command pthread_cancel to stop the child thread and the child thread really starts to response the cancellation after the command pthread_join is invoked.

At the moment, the main thread runs to the line immediately after pthread_join, the child thread is running inside the loop of the following code,

    for(i = 0; i < 10; i++) {
        printf("Thread is still running (%d)...\n", i);
        sleep(1);
    }

I don't see any checking statement inside this loop, but the main thread still is able to cancel the child thread. I assume that the POSIX multithread system has a checking system internally so that it can terminate the child thread when the pthread_join is called in the main thread.

Question>

Basically, I need to understand how the child thread can be cancelled inside the loop without itself checking any flags.

Also, please correct my description if anything is wrong.

like image 537
q0987 Avatar asked Jul 10 '11 15:07

q0987


1 Answers

What's happening is that your loop contains at least one cancellation point, sleep (and possibly two, since printf is an optional cancellation point).

Being a cancellation point means the function contains logic similar to:

if (thread_local_cancellation_flag) {
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE);
    pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED);
    pthread_exit(PTHREAD_CANCELED);
}

In reality, however, it's a little bit more complicated, because if the cancellation request arrives while the function is "waiting" or "blocking" for some event to take place (like sleep time to expire, or input from a socket), it must be acted upon. Thus some sort of asynchronous delivery mechanism is required, and the typical implementation is to use signals for this, but it's actually extremely difficult to get right, and popular implementations don't do so well. For some ugly corner cases in glibc which other implementations probably share, see this bug report:

http://sourceware.org/bugzilla/show_bug.cgi?id=12683

In your case, what's almost surely happening is that the cancellation request arrives (via a signal) while the thread is waiting in sleep, and a signal handler runs, determines that it's in the middle of a cancellable operation, and acts on the cancellation request.

like image 137
R.. GitHub STOP HELPING ICE Avatar answered Oct 04 '22 05:10

R.. GitHub STOP HELPING ICE