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)...
Thr开发者_如何学Pythonead 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.
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.
Please read pthread_cancel manual page first. It explains a lot. Specifically to your question, there shall be no checking statement inside the loop. I haven't checked the Linux implementation but the rational thing to do this would be to send a thread a signal requesting thread to stop/cancel. If in signal handler thread is determined to be the state it cannot be cancelled then request is queued. Once you call any function that is a cancellation point and new state is determined to be cancellable, that queue is checked and if request to cancel is found in the queue - thread is cancelled. Basically, not cancellable state is a critical section. In your case, all of your threads are cancelled when calling sleep ()
, as that is a cancellation point. See pthreads (7).
精彩评论