取消线程
取消操作允许线程请求终止其所在进程中的任何其他线程。不希望或不需要对一组相关的线程执行进一步操作时,可以选择执行取消操作。例如,用户请求关闭或退出正在运行的应用程序。另一个示例是完成由许多线程执行的任务。其中的某个线程可能最终完成了该任务,而其它线程还在继续运行。由于正在运行的线程此时没有任何用处,因此取消这个线程。
取消点
-
通过pthread_testcancel调用以编程方式建立线程取消点。 -
线程等待pthread_cond_wait或pthread_cond_timewait()中的特定条件。 -
被sigwait(2)阻塞的函数 -
一些标准的库调用。通常,这些调用包括线程可基于阻塞的函数。
pthread_testcancel();
retcode = read(fd, buffer, length);
pthread_testcancel();
注意:
程序设计方面的考虑
如果线程处于无限循环中,且循环体内没有执行至取消点的必然路径,则线程无法由外部其他线程的取消请求而终止。因此在这样的循环体的必经路径上应该加入pthread_testcancel()调用。
放置取消点
- 异步
- 执行序列中按照标准定义的点
- 调用pthread_cancel()
取消线程方面的函数
int pthread_cancel(pthread_t thread);
返回:
成功之后返回0。失败返回错误号,错误号说明如下:
ESRCH:没有找到线程ID相对应的线程。
int pthread_setcancelstate(int state, int *oldstate);
设置本线程对信号的反应,状态有两种:
返回:
int pthread_setcanceltype(int type, int *oldtype);
类型有两种,只有在PTHREAD_CANCEL_ENABLE状态下有效
PTHREAD_CANCEL_ASYNCHRONOUS
返回:
void pthread_testcancel(void);
当线程取消功能处于启用状态且取消状态设置为延迟状态时,pthread_testcancel()函数有效。如果在取消功能处处于禁用状态下调用pthread_testcancel(),则该函数不起作用。
请务必仅在线程取消线程操作安全的序列中插入pthread_testcancel()。除通过pthread_testcancel()调用以编程方式建立的取消点意外,pthread标准还指定了几个取消点。
测试退出点,就是测试cancel信号
线程取消点例子
10
11 {
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31}
32
33
34
35 int
36
37 {
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53}
54
(printf系统调用可引起阻塞,是系统默认的取消点,但是最好是在其前后加pthread_testcancel()函数)
10
11 {
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31}
32
33
34
35 int
36
37 {
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53}
54
55
(在异步取消时,线程不会去寻找取消点,而是立即取消)
10
11 {
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31}
32
33
34
35 int
36
37 {
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55}
56
57
(不可取消)
10
11{
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31}
32
33
34
35int
36
37{
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55}
56
57
10
11 {
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33}
34
35
36
37 int
38
39 {
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57}
58
不论是可预见的线程终止还是异常终止,都会存在资源释放的问题,在不考虑因运行出错而退出的前提下,如何保证线程终止时能顺利的释放掉自己所占用的资源,特别是锁资源,就是一个必须考虑解决的问题。
最经常出现的情形是资源独占锁的使用:线程为了访问临界资源而为其加上锁,但在访问过程中被外界取消,如果线程处于响应取消状态,且采用异步方式响应,或者在打开独占锁以前的运行路径上存在取消点,则该临界资源将永远处于锁定状态得不到释放。外界取消操作是不可预见的,因此的确需要一个机制来简化用于资源释放的编程。
在POSIX线程API中提供了一个pthread_cleanup_push()/pthread_cleanup_pop()函数对用于自动释放资源--从pthread_cleanup_push()的调用点到pthread_cleanup_pop()之间的程序段中的终止动作(包括调用pthread_exit()和取消点终止)都将执行pthread_cleanup_push()所指定的清理函数。