pthread_cancel

 1 #include <pthread.h>
 2 #include <stdio.h>
 3 #include<stdlib.h>
 4 #include <unistd.h>
 5 
 6 static void checkResults(char *string, int rc) {
 7     if (rc) {
 8         printf("Error on : %s, rc=%d",
 9                 string, rc);
10         exit(EXIT_FAILURE);
11     }   
12     return;
13 }
14 
15 void *threadfunc(void *parm)
16 {
17     printf("Entered secondary thread\n");
18     int cnt = 0;
19     while (1) {
20         printf("Secondary thread is looping, %d\n", cnt);
21         cnt ++; 
22         pthread_testcancel();
23         sleep(1);
24     }   
25     return NULL;
26 }
27 
28 int main(int argc, char **argv)
29 {
30     pthread_t             thread;
31     int                   rc=0;
32     void                  *thread_result;
33 
34     printf("Entering testcase\n");
35 
36     /* Create a thread using default attributes */
37     printf("Create thread using the NULL attributes\n");
38     rc = pthread_create(&thread, NULL, threadfunc, NULL);
39     checkResults("pthread_create(NULL)\n", rc);
40 
41     /* sleep() is not a very robust way to wait for the thread */
42     sleep(4);
43 
44     printf("Cancel the thread\n");
45     rc = pthread_cancel(thread);
46     checkResults("pthread_cancel()\n", rc);
47 
48     rc = pthread_join(thread, &thread_result);
49     if (thread_result == PTHREAD_CANCELED)
50         printf(" return PTHREAD_CANCELED\n");
51 
52     /* sleep() is not a very robust way to wait for the thread */
53     sleep(3);
54     printf("Main completed\n");
55     return 0;
56 }

 

参考

 

http://www.cnblogs.com/Creator/archive/2012/03/21/2408413.html

 

pthread_cancel可以单独使用,因为在很多系统函数里面本身就有很多的取消点断点,当调用这些系统函数时就会命中其内部的断点来结束线程,如下面的代码中,即便注释掉我们自己设置的断点pthread_testcancel()程序还是一样的会被成功的cancel掉,因为printf函数内部有取消点(如果大家想了解更多的函数的取消点情况,可以阅读《Unix高级环境编程》的线程部分)

上班的代码去掉pthread_testcancel()和print程序还是一样的会被成功的cancel掉,因为sleep本身内部也有取消点吧。

 

当把上述程序中while(1)中删除sleep()和print函数以及pthread_testcancel()后,线程无法被取消。。证明while(1)实现没有取消点。

 

pthread_testcancel() 主要针对那种计算密集型的

     描述:函数在运行的线程中创建一个取消点,如果cancellation无效则此函数不起作用。
            
            pthread的建议是:如果一个函数是阻塞的,那么你必须在这个函数前后建立 “ 取消点 ”, 比如:
                            printf("sleep\n");
                           pthread_testcancel();
                            sleep(10);
                            pthread_testcancel();
                             printf("wake \n");
            在执行到pthread_testcancel的位置时,线程才可能响应cancel退出进程。
            
            对于一些函数来说本身就是有cancellation point 的,那么可以不管,但是大部分还是没有的,
            所以要使用pthread_testcancel来设置一个取消点,那么也并不是对于所有的函数都是有效的,
            对于有延时的函数才是有效的,更清楚的说是有时间让pthread_cancel响应才是OK的!

 1 #include <pthread.h>
 2 #include <stdio.h>
 3 #include<stdlib.h>
 4 #include <unistd.h>
 5 
 6 #include <pthread.h>
 7 void testPointerSize()
 8 {
 9     void *tret;
10     printf("size of pointer in x86-64:%d\n",sizeof(tret));
11     //result is 8 in x86-64.
12     //which is 4 in x86-32.
13 
14     printf("size of int in x86-64:%d\n",sizeof(int));
15     //result is 4 in x86-64.
16     //which is also 4 in x86-32.
17 }
18 void cleanup(void *arg)
19 {
20     printf("cleanup:%s\n",(char *)arg);
21 }
22 
23 void * thr_fn4(void *arg)
24 {
25     printf("thread 4 start\n");
26     pthread_cleanup_push(cleanup, "thread 4 first handler");
27     pthread_cleanup_push(cleanup, "thread 4 second handler");
28     pthread_cleanup_push(cleanup, "thread 4 3th handler");
29 
30     while(1)
31     {   
32         usleep(10);
33     }   
34 
35     pthread_cleanup_pop(0);
36     pthread_cleanup_pop(1);
37     pthread_cleanup_pop(0);
38     pthread_exit((void *)4);
39     //pthread_exit() here will triger cleanup second handler.
40 }
41 
42 int main(void)
43 {
44     testPointerSize();
45     int err;
46     pthread_t tid1, tid2, tid3, tid4;
47     void *tret;
48 
49     err = pthread_create(&tid4, NULL, thr_fn4, (void *)4);
50     sleep(1);
51     pthread_cancel(tid4);
52     err = pthread_join(tid4, &tret);
53     printf("thread 4 exit code %d\n",(int)tret);
54     if(tret == PTHREAD_CANCELED)
55         printf("thread is cancelled\n");
56 
57     return 0;
58 }

输出:

size of pointer in x86-64:4
size of int in x86-64:4
thread 4 start
cleanup:thread 4 3th handler
cleanup:thread 4 second handler
cleanup:thread 4 first handler
thread 4 exit code -1
thread is cancelled

可见,PTHREAD_CANCELED 被定义成-1.

 

基本概念
pthread_cancel调用并不等待线程终止,它只提出请求。线程在取消请求(pthread_cancel)发出后会继续运行,
直到到达某个取消点(CancellationPoint)。取消点是线程检查是否被取消并按照请求进行动作的一个位置.


与线程取消相关的pthread函数
int pthread_cancel(pthread_t thread)
发送终止信号给thread线程,如果成功则返回0,否则为非0值。发送成功并不意味着thread会终止。

int pthread_setcancelstate(int state,   int *oldstate)   
设置本线程对Cancel信号的反应,state有两种值:PTHREAD_CANCEL_ENABLE(缺省)和PTHREAD_CANCEL_DISABLE,
分别表示收到信号后设为CANCLED状态和忽略CANCEL信号继续运行;old_state如果不为NULL则存入原来的Cancel状态以便恢复。  

int pthread_setcanceltype(int type, int *oldtype)   
设置本线程取消动作的执行时机,type由两种取值:PTHREAD_CANCEL_DEFFERED和PTHREAD_CANCEL_ASYCHRONOUS,仅当Cancel状态为Enable时有效,分别表示收到信号后继续运行至下一个取消点再退出和立即执行取消动作(退出);oldtype如果不为NULL则存入运来的取消动作类型值。  

void pthread_testcancel(void)
是说pthread_testcancel在不包含取消点,但是又需要取消点的地方创建一个取消点,以便在一个没有包含取消点的执行代码线程中响应取消请求.
线程取消功能处于启用状态且取消状态设置为延迟状态时,pthread_testcancel()函数有效。
如果在取消功能处处于禁用状态下调用pthread_testcancel(),则该函数不起作用。
请务必仅在线程取消线程操作安全的序列中插入pthread_testcancel()。除通过pthread_testcancel()调用以编程方式建立的取消点意外,pthread标准还指定了几个取消点。测试退出点,就是测试cancel信号.


取消点:
线程取消的方法是向目标线程发Cancel信号,但如何处理Cancel信号则由目标线程自己决定,或者忽略、或者立即终止、或者继续运行至Cancelation-point(取消点),由不同的Cancelation状态决定。

线程接收到CANCEL信号的缺省处理(即pthread_create()创建线程的缺省状态)是继续运行至取消点,也就是说设置一个CANCELED状态,线程继续运行,只有运行至Cancelation-point的时候才会退出。

pthreads标准指定了几个取消点,其中包括:
(1)通过pthread_testcancel调用以编程方式建立线程取消点。 
(2)线程等待pthread_cond_wait或pthread_cond_timewait()中的特定条件。 
(3)被sigwait(2)阻塞的函数 
(4)一些标准的库调用。通常,这些调用包括线程可基于阻塞的函数。 
  
缺省情况下,将启用取消功能。有时,您可能希望应用程序禁用取消功能。如果禁用取消功能,则会导致延迟所有的取消请求,
直到再次启用取消请求。  
根据POSIX标准,pthread_join()、pthread_testcancel()、pthread_cond_wait()、pthread_cond_timedwait()、sem_wait()、sigwait()等函数以及
read()、write()等会引起阻塞的系统调用都是Cancelation-point,而其他pthread函数都不会引起Cancelation动作。
但是pthread_cancel的手册页声称,由于LinuxThread库与C库结合得不好,因而目前C库函数都不是Cancelation-point;但CANCEL信号会使线程从阻塞的系统调用中退出,并置EINTR错误码,因此可以在需要作为Cancelation-point的系统调用前后调用pthread_testcancel(),从而达到POSIX标准所要求的目标.
即如下代码段:
pthread_testcancel();
retcode = read(fd, buffer, length);
pthread_testcancel();

注意:
程序设计方面的考虑,如果线程处于无限循环中,且循环体内没有执行至取消点的必然路径,则线程无法由外部其他线程的取消请求而终止。因此在这样的循环体的必经路径上应该加入pthread_testcancel()调用.


取消类型(Cancellation Type)

我们会发现,通常的说法:某某函数是 Cancellation Points,这种方法是容易令人混淆的。
因为函数的执行是一个时间过程,而不是一个时间点。其实真正的 Cancellation Points 只是在这些函数中 Cancellation Type 被修改为 PHREAD_CANCEL_ASYNCHRONOUS 和修改回 PTHREAD_CANCEL_DEFERRED 中间的一段时间。

POSIX的取消类型有两种,一种是延迟取消(PTHREAD_CANCEL_DEFERRED),这是系统默认的取消类型,即在线程到达取消点之前,不会出现真正的取消;另外一种是异步取消(PHREAD_CANCEL_ASYNCHRONOUS),使用异步取消时,线程可以在任意时间取消。

 

 

http://www.cnblogs.com/mydomain/archive/2011/08/15/2139830.html

一个 pthread_cancel 引起的线程死锁【整理转载】

posted @ 2014-07-31 15:38  穆穆兔兔  阅读(578)  评论(0编辑  收藏  举报