Posted on 2010-01-31 17:08
LibraLiang 阅读(1032)
评论(0) 编辑 收藏 引用 所属分类:
UNIX线程
取消线程
取消操作允许线程请求终止其所在进程中的任何其他线程。不希望或不需要对一组相关的线程执行进一步操作时,可以选择执行取消操作。例如,用户请求关闭或退出正在运行的应用程序。另一个示例是完成由许多线程执行的任务。其中的某个线程可能最终完成了该任务,而其它线程还在继续运行。由于正在运行的线程此时没有任何用处,因此取消这个线程。
取消点
仅当取消操作安全时才应取消线程。pthreads标准指定了几个取消点,其中包括:
- 通过pthread_testcancel调用以编程方式建立线程取消点。
- 线程等待pthread_cond_wait或pthread_cond_timewait()中的特定条件。
- 被sigwait(2)阻塞的函数
- 一些标准的库调用。通常,这些调用包括线程可基于阻塞的函数。
缺省情况下,将启用取消功能。有时,您可能希望应用程序禁用取消功能。如果禁用取消功能,则会导致延迟所有的取消请求,直到再次启用取消请求。 根据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()调用。
放置取消点
执行取消操作存在一定的危险。大多数危险都与完全恢复不变量和释放共享资源有关。取消线程时一定要格外小心,否则可能会使互斥保留为锁定状态,从而导致死锁状态。或者,已取消的线程可能保留已分配的内存区域,但是系统无法识别这一部分内存,从而无法释放它。
标准C库指定了一个取消接口用于以编程方式允许或禁止取消功能。该库定义的取消点是一组可能会执行取消操作的点。该库还允许定义取消处理程序的范围,以确保这些处理程序在预期的时间和位置运行。取消处理程序提供的清理服务可以将资源和状态恢复到与起点一致的状态。
必须对应用程序有一定的了解,才能放置取消点并执行取消处理程序。互斥肯定不是取消点,只应当在必要时使之保留尽可能短的时间。请将异步取消区域限制在没有外部依赖性的序列,因为外部依赖性可能会产生挂起的资源或未解决的状态条件。在从某个备用的嵌套取消状态返回时,一定要小心地恢复取消状态。该接口提供便于进行恢复的功能:pthread_setcancelstate(3C) 在所引用的变量中保留当前的取消状态,pthread_setcanceltype(3C) 以同样的方式保留当前的取消类型。
在以下三种情况下可能会执行取消操作:
- 异步
- 执行序列中按照标准定义的点
- 调用pthread_cancel()
取消线程方面的函数
int pthread_cancel(pthread_t thread);
返回:
成功之后返回0。失败返回错误号,错误号说明如下:
ESRCH:没有找到线程ID相对应的线程。
int pthread_setcancelstate(int state, int *oldstate);设置本线程对信号的反应
状态有两种:
PTHREAD_CANCEL_ENABLE 默认,收到cancel信号马上设置退出状态。
PTHREAD_CANCEL_DISABLE 收到cancel信号继续运行。
返回:
成功之后返回0。失败返回错误号,错误号说明如下:
EINVAL:状态不是PTHREAD_CANCEL_ENABLE或者PTHREAD_CANCEL_DISABLE
int pthread_setcanceltype(int type, int *oldtype);
类型有两种,只有在PTHREAD_CANCEL_ENABLE状态下有效
PTHREAD_CANCEL_ASYNCHRONOUS 立即执行取消信号
PTHREAD_CANCEL_DEFERRED 运行到下一个取消点
返回:
成功之后返回0.失败返回错误号,错误号说明如下:
EINVAL:状态不是PTHREAD_CANCEL_ASYNCHRONOUS或者PTHREAD_CANCEL_DEFERRED
void pthread_testcancel(void);
当线程取消功能处于启用状态且取消状态设置为延迟状态时,pthread_testcancel()函数有效。如果在取消功能处处于禁用状态下调用pthread_testcancel(),则该函数不起作用。
请务必仅在线程取消线程操作安全的序列中插入pthread_testcancel()。除通过pthread_testcancel()调用以编程方式建立的取消点意外,pthread标准还指定了几个取消点。
测试退出点,就是测试cancel信号
线程取消点例子
l 线程中没有取消点
1#include <pthread.h>
2
3#include <stdio.h>
4
5#include <unistd.h>
6
7
8
9void* thr(void* arg)
10
11{
12
13 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
14
15 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL);
16
17
18
19 while(1)
20
21 {
22
23 ;
24
25 }
26
27 printf("thread is not running\n");
28
29 sleep(2);
30
31}
32
33
34
35int main()
36
37{
38
39 pthread_t th1;
40
41 int err;
42
43 err = pthread_create(&th1,NULL,thr,NULL);
44
45 pthread_cancel(th1);
46
47 pthread_join(th1,NULL);
48
49 printf("Main thread is exit\n");
50
51 return 0;
52
53}
54
l 子线程中有取消点
1#include <pthread.h>
2
3#include <stdio.h>
4
5#include <unistd.h>
6
7
8
9void* thr(void* arg)
10
11{
12
13 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
14
15 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL);
16
17
18
19 while(1)
20
21 {
22
23 printf("thread is running\n");
24
25 }
26
27 printf("thread is not running\n");
28
29 sleep(2);
30
31}
32
33
34
35int main()
36
37{
38
39 pthread_t th1;
40
41 int err;
42
43 err = pthread_create(&th1,NULL,thr,NULL);
44
45 pthread_cancel(th1);
46
47 pthread_join(th1,NULL);
48
49 printf("Main thread is exit\n");
50
51 return 0;
52
53}
54
55
l 异步取消(HP没有成功)
1#include <pthread.h>
2
3#include <stdio.h>
4
5#include <unistd.h>
6
7
8
9void* thr(void* arg)
10
11{
12
13 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
14
15 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
16
17
18
19 while(1)
20
21 {
22
23 ;
24
25 }
26
27 printf("thread is not running\n");
28
29 sleep(2);
30
31}
32
33
34
35int main()
36
37{
38
39 pthread_t th1;
40
41 int err;
42
43 err = pthread_create(&th1,NULL,thr,NULL);
44
45 pthread_cancel(th1);
46
47 pthread_join(th1,NULL);
48
49 sleep(1);
50
51 printf("Main thread is exit\n");
52
53 return 0;
54
55}
56
57
l 设置不可取消
1#include <pthread.h>
2
3#include <stdio.h>
4
5#include <unistd.h>
6
7
8
9void* thr(void* arg)
10
11{
12
13 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
14
15 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL);
16
17
18
19 while(1)
20
21 {
22
23 printf("thread is running\n");
24
25 }
26
27 printf("thread is not running\n");
28
29 sleep(2);
30
31}
32
33
34
35int main()
36
37{
38
39 pthread_t th1;
40
41 int err;
42
43 err = pthread_create(&th1,NULL,thr,NULL);
44
45 pthread_cancel(th1);
46
47 pthread_join(th1,NULL);
48
49 sleep(1);
50
51 printf("Main thread is exit\n");
52
53 return 0;
54
55}
56
57
l 设置取消点
1#include <pthread.h>
2
3#include <stdio.h>
4
5#include <unistd.h>
6
7
8
9void* thr(void* arg)
10
11{
12
13 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,NULL);
14
15 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,NULL);
16
17
18
19 while(1)
20
21 {
22
23 ;
24
25 pthread_testcancel();
26
27 }
28
29 printf("thread is not running\n");
30
31 sleep(2);
32
33}
34
35
36
37int main()
38
39{
40
41 pthread_t th1;
42
43 int err;
44
45 err = pthread_create(&th1,NULL,thr,NULL);
46
47 pthread_cancel(th1);
48
49 pthread_join(th1,NULL);
50
51 sleep(1);
52
53 printf("Main thread is exit\n");
54
55 return 0;
56
57}
58