7、取消点的进一步讨论

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

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

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

(1)什么是线程取消点

根据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);

2)与线程取消相关的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_DEFFEREDPTHREAD_CANCEL_ASYCHRONOUS,仅当Cancel状态为Enable时有效,分别表示收到信号后继续运行至下一个取消点再退出和立即执行取消动作(退出);oldtype如果不为NULL则存入运来的取消动作类型值。  

void pthread_testcancel(void)

Calling pthread_testcancel() creates a cancellation point within the calling thread, so that a thread that is otherwise executing code that contains no cancellation points will respond to a cancellation request.

If cancelability is disabled (using pthread_setcancelstate(3)), or no cancellation request is pending, then a call to pthread_cancel(3) has no effect.

也就是说pthread_testcancel在不包含取消点,但是又需要取消点的地方创建一个取消点,以便在一个没有包含取消点的执行代码线程中响应取消请求。

示例代码【3

img_1c53668bcee393edac0d7b3b3daff1ae.gif img_405b18b4b6584ae338e0f6ecaf736533.gif View Code
#include <pthread.h>
#include
<sys/types.h>
#include
<stdio.h>
#include
<stdlib.h>
#include
<unistd.h>
#include
<errno.h>

#define handle_error_en(en, msg) \
do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)

static int done = 0;
static int cleanup_pop_arg = 0;
static int cnt = 0;

static void
cleanup_handler(
void *arg)
{
printf(
"Called clean-up handler\n");
cnt
= 0;
}

static void *
thread_start(
void *arg)
{
time_t start, curr;
printf(
"New thread started\n");
pthread_cleanup_push(cleanup_handler, NULL);
curr
= start = time(NULL);

while (!done) {
pthread_testcancel();
/* A cancellation point */
if (curr < time(NULL))
{
curr
= time(NULL);
printf(
"cnt = %d\n", cnt); /* A cancellation point */
cnt
++;
}
}

pthread_cleanup_pop(cleanup_pop_arg);
return NULL;
}

int
main(
int argc, char *argv[])
{
pthread_t thr;
int s;
void *res;

s
= pthread_create(&thr, NULL, thread_start, NULL);
if (s != 0)
handle_error_en(s,
"pthread_create");

sleep(
2); /* Allow new thread to run a while */

if (argc > 1)
{
if (argc > 2)
cleanup_pop_arg
= atoi(argv[2]);
done
= 1;

}
else
{
printf(
"Canceling thread\n");
s
= pthread_cancel(thr);
if (s != 0)
handle_error_en(s,
"pthread_cancel");
}

s
= pthread_join(thr, &res);
if (s != 0)
handle_error_en(s,
"pthread_join");

if (res == PTHREAD_CANCELED)
printf(
"Thread was canceled; cnt = %d\n", cnt);
else
printf(
"Thread terminated normally; cnt = %d\n", cnt);
exit(EXIT_SUCCESS);
}

示例代码跟踪

img_1c53668bcee393edac0d7b3b3daff1ae.gif img_405b18b4b6584ae338e0f6ecaf736533.gif View Code
[root@localhost CFunctionTest]# ./thread
New thread started
cnt
= 0
cnt
= 1
Canceling thread
Called clean
-up handler
Thread was canceled; cnt
= 0
[root@localhost CFunctionTest]# gdb thread
(gdb) b
18
//...
(gdb) r
Starting program:
/home/***/a***/CFunctionTest/thread
[Thread debugging
using libthread_db enabled]

Breakpoint
6, main (argc=1, argv=0xbffff374) at testthread.cpp:54
54 s = pthread_create(&thr, NULL, thread_start, NULL);
Missing separate debuginfos, use: debuginfo
-install glibc-2.12.90-17.i686 libgcc-4.5.1-4.fc14.i686 libstdc++-4.5.1-4.fc14.i686
(gdb) n
[New Thread
0xb7fecb70 (LWP 4845)]
New thread started
[Switching to Thread
0xb7fecb70 (LWP 4845)]

Breakpoint
2, thread_start (arg=0x0) at testthread.cpp:29
29 pthread_cleanup_push(cleanup_handler, NULL);
(gdb) n
31 curr = start = time(NULL);
(gdb) n
33 while (!done) {
(gdb) n

Breakpoint
3, thread_start (arg=0x0) at testthread.cpp:34
34 pthread_testcancel(); /* A cancellation point */
(gdb) n
Canceling thread
[Switching to Thread
0xb7fee6d0 (LWP 4840)]

Breakpoint
7, main (argc=1, argv=0xbffff374) at testthread.cpp:70
70 s = pthread_cancel(thr);
(gdb) n
cnt
= 0
[Switching to Thread
0xb7fecb70 (LWP 4845)]

Breakpoint
4, thread_start (arg=0x0) at testthread.cpp:39
39 cnt++;
(gdb) n
33 while (!done) {
(gdb) n

Breakpoint
3, thread_start (arg=0x0) at testthread.cpp:34
34 pthread_testcancel(); /* A cancellation point */
(gdb) n
35 if (curr < time(NULL))
(gdb) n
37 curr = time(NULL);
(gdb) n
38 printf("cnt = %d\n", cnt); /* A cancellation point */
(gdb) n
cnt
= 1
[Switching to Thread
0xb7fee6d0 (LWP 4840)]

Breakpoint
8, main (argc=1, argv=0xbffff374) at testthread.cpp:75
75 s = pthread_join(thr, &res);
(gdb) n
[Switching to Thread
0xb7fecb70 (LWP 4845)]

Breakpoint
4, thread_start (arg=0x0) at testthread.cpp:39
39 cnt++;
(gdb) n
33 while (!done) {
(gdb) n

Breakpoint
3, thread_start (arg=0x0) at testthread.cpp:34
34 pthread_testcancel(); /* A cancellation point */
(gdb) n

Breakpoint
1, cleanup_handler (arg=0x0) at testthread.cpp:18
18 printf("Called clean-up handler\n");
(gdb) n
Called clean
-up handler
19 cnt = 0;
(gdb) n
20 }
(gdb) n

参考:

1 http://blog.csdn.net/yanook/article/details/6589798

2http://blog.csdn.net/yulanarti/article/details/6197769

3http://www.kernel.org/doc/man-pages/online/pages/man3/pthread_cleanup_push.3.html

相关实践学习
阿里云图数据库GDB入门与应用
图数据库(Graph Database,简称GDB)是一种支持Property Graph图模型、用于处理高度连接数据查询与存储的实时、可靠的在线数据库服务。它支持Apache TinkerPop Gremlin查询语言,可以帮您快速构建基于高度连接的数据集的应用程序。GDB非常适合社交网络、欺诈检测、推荐引擎、实时图谱、网络/IT运营这类高度互连数据集的场景。 GDB由阿里云自主研发,具备如下优势: 标准图查询语言:支持属性图,高度兼容Gremlin图查询语言。 高度优化的自研引擎:高度优化的自研图计算层和存储层,云盘多副本保障数据超高可靠,支持ACID事务。 服务高可用:支持高可用实例,节点故障迅速转移,保障业务连续性。 易运维:提供备份恢复、自动升级、监控告警、故障切换等丰富的运维功能,大幅降低运维成本。 产品主页:https://www.aliyun.com/product/gdb
目录
相关文章
|
12月前
|
SQL 安全 算法
网络安全与信息安全的全面解析:应对漏洞、加密技术及提升安全意识的策略
本文深入探讨了网络安全和信息安全的重要性,详细分析了常见的网络安全漏洞以及其利用方式,介绍了当前流行的加密技术及其应用,并强调了培养良好安全意识的必要性。通过综合运用这些策略,可以有效提升个人和企业的网络安全防护水平。
|
存储 缓存 安全
ConcurrentHashMap:使用方法和底层原理详解
ConcurrentHashMap:使用方法和底层原理详解
406 1
|
数据可视化 物联网 Swift
谷歌发布开源LLM Gemma,魔搭社区评测+最佳实践教程来啦!
Gemma是由Google推出的一系列轻量级、先进的开源模型,他们是基于 Google Gemini 模型的研究和技术而构建。
|
11月前
|
API 数据安全/隐私保护 开发者
实时获取小红书详情 API 数据
小红书详情API数据获取指南:注册开发者账号,创建应用并申请接口权限,构建请求获取笔记详情,使用Python等语言处理响应数据。需遵守使用规则,注意调用频率和数据安全。
|
12月前
|
机器学习/深度学习 数据采集 数据挖掘
深度学习之地形分类与变化检测
基于深度学习的地形分类与变化检测是遥感领域的一个关键应用,利用深度学习技术从卫星、无人机等地球观测平台获取的遥感数据中自动分析地表特征,并识别地形的变化。这一技术被广泛应用于城市规划、环境监测、灾害预警、土地利用变化分析等领域。
705 0
|
12月前
|
机器学习/深度学习 计算机视觉
一文详解残差网络
残差网络(ResNet)源于2016年的论文《Deep Residual Learning for Image Recognition》,旨在解决深层网络中的梯度消失和爆炸问题。通过引入残差块,即在网络中添加跳跃连接,使得信息可以直接跨过多层传递,从而有效解决了网络加深导致的训练困难。ResNet不仅显著提高了模型性能,还促进了深度学习领域的发展。
1603 3
|
12月前
|
存储 SQL 安全
探索ConcurrentHashMap:从底层到应用的深度剖析
【10月更文挑战第6天】在Java并发编程中,ConcurrentHashMap是一个非常重要的数据结构,它提供了一种线程安全的哈希表实现。本文将深入探讨ConcurrentHashMap的底层存储结构、红黑树转换时机、数组扩容时机、核心属性sizeCtl、数组初始化、DCL操作、散列算法、写入操作的并发安全、计数器的安全机制以及size方法的实现策略。
199 1
|
安全 Linux
在Linux中,suid、sgid和sticky bit这几个术语意思?
在Linux中,suid、sgid和sticky bit这几个术语意思?
|
安全 数据安全/隐私保护
基于RBAC实现权限系统
基于RBAC实现权限系统
747 0
|
API 开发工具 git
`black`是一个不受约束的Python代码格式化工具。它自动将Python代码格式化为PEP 8样式,但具有一些额外的规则,旨在使代码更加一致和易读。
`black`是一个不受约束的Python代码格式化工具。它自动将Python代码格式化为PEP 8样式,但具有一些额外的规则,旨在使代码更加一致和易读。