申明:本学习笔记是在该教程的基础上结合自己的学习情况进行的总结,不是原创,想要看原版的请看C语言中文网的多线程编程(C语言+Linux),该网站有很多好的编程学习教程,尤其是关于C语言的。

在《终止线程执行(3种方法)》一节中,我们对 pthread_cancel() 函数的功能和用法做了详细的介绍。总的来说,通过调用 pthread_cancel() 函数,一个线程可以向同进程内的另一个线程发送“终止执行”的信号(Cancel 信号),使目标线程结束执行。

实际使用 pthread_cancel() 函数时,很多读者会发现“Cancel 信号成功发送,但目标线程并未立即终止执行”等类似的问题举个例子,在 Linux 环境中执行如下程序:

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>   //调用 sleep() 函数
void * thread_Fun(void * arg) {printf("新建线程开始执行\n");//插入无限循环的代码,测试 pthread_cancel()函数的有效性while(1);
}
int main()
{pthread_t myThread;void * mess;int value;int res;res = pthread_create(&myThread, NULL, thread_Fun, NULL);if (res != 0) {printf("线程创建失败\n");return 0;}sleep(1);//令 myThread 线程终止执行res = pthread_cancel(myThread);if (res != 0) {printf("终止 myThread 线程失败\n");return 0;}printf("等待 myThread 线程执行结束:\n");res = pthread_join(myThread, &mess);if (res != 0) {printf("等待线程失败\n");return 0;}if (mess == PTHREAD_CANCELED) {printf("myThread 线程被强制终止\n");}else {printf("error\n");}return 0;
}

程序中,主线程( main() 函数)试图调用 pthread_cancel() 函数终止 myThread 线程执行。从运行结果不难发现,pthread_cancel() 函数成功发送了 Cancel 信号,但目标线程仍在执行。

也就是说,接收到 Cancel 信号的目标线程并没有立即处理该信号,或者说目标线程根本没有理会此信号。解决类似的问题,我们就需要搞清楚目标线程对 Cancel 信号的处理机制。

根据上节的内容,pthread_join会阻塞调用它的线程,因此程序在执行完printf(“等待 myThread 线程执行结束:\n”);后就会一直阻塞在res = pthread_join(myThread, &mess);等待目标线程myThread执行完毕

线程对Cancel信号的处理

对于默认属性的线程,当有线程借助 pthread_cancel() 函数向它发送 Cancel 信号时,它并不会立即结束执行,而是选择在一个适当的时机结束执行。

所谓适当的时机,POSIX 标准中规定,当线程执行一些特殊的函数时,会响应 Cancel 信号并终止执行,比如常见的 pthread_join()、pthread_testcancel()、sleep()、system() 等,POSIX 标准称此类函数为“cancellation points”(中文可译为“取消点”)。

POSIX 标准中明确列举了所有可以作为取消点的函数,这里不再一一罗列,感兴趣的读者可以自行查阅 POSIX 标准手册。

此外,<pthread.h> 头文件还提供有 pthread_setcancelstate() 和 pthread_setcanceltype() 这两个函数,我们可以手动修改目标线程处理 Cancel 信号的方式。

1、pthread_setcancelstate()函数

借助 pthread_setcancelstate() 函数,我们可以令目标线程处理 Cancal 信号,也可以令目标线程不理会其它线程发来的 Cancel 信号。

pthread_setcancelstate() 函数的语法格式如下:

int pthread_setcancelstate( int state , int * oldstate );
  1. state 参数有两个可选值,分别是:
  • PTHREAD_CANCEL_ENABLE(默认值):当前线程会处理其它线程发送的 Cancel 信号;
  • PTHREAD_CANCEL_DISABLE:当前线程不理会其它线程发送的 Cancel 信号,直到线程状态重新调整为 PTHREAD_CANCEL_ENABLE 后,才处理接收到的 Cancel 信号。
  1. oldtate 参数用于接收线程先前所遵循的 state 值,通常用于对线程进行重置。如果不需要接收此参数的值,置为 NULL 即可。

pthread_setcancelstate() 函数执行成功时,返回数字 0,反之返回非零数。

2、pthread_setcanceltype()函数

当线程会对 Cancel 信号进行处理时,我们可以借助 pthread_setcanceltype() 函数设置线程响应 Cancel 信号的时机。

pthread_setcanceltype() 函数的语法格式如下:

int pthread_setcanceltype( int type , int * oldtype );
  1. type 参数有两个可选值,分别是:
  • PTHREAD_CANCEL_DEFERRED(默认值):当线程执行到某个可作为取消点的函数时终止执行;
  • PTHREAD_CANCEL_ASYNCHRONOUS:线程接收到 Cancel 信号后立即结束执行。
  1. oldtype 参数用于接收线程先前所遵循的 type 值,如果不需要接收该值,置为 NULL 即可。

pthread_setcanceltype() 函数执行成功时,返回数字 0,反之返回非零数。

接下来通过一个实例给大家演示以上两个函数的功能和用法:

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>   //调用 sleep() 函数void * thread_Fun(void * arg) {printf("新建线程开始执行\n");int res;//设置线程为可取消状态res = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);if (res != 0) {printf("修改线程可取消状态失败\n");return  NULL;}//设置线程接收到 Cancel 信号后立即结束执行res = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);if (res != 0) {printf("修改线程响应 Cancel 信号的方式失败\n");return  NULL;}while (1);return NULL;
}
int main()
{pthread_t myThread;void * mess;int value;int res;res = pthread_create(&myThread, NULL, thread_Fun, NULL);if (res != 0) {printf("线程创建失败\n");return 0;}sleep(1);//向 myThread 线程发送 Cancel 信号res = pthread_cancel(myThread);if (res != 0) {printf("终止 myThread 线程失败\n");return 0;}//等待 myThread 线程执行结束,获取返回值res = pthread_join(myThread, &mess);if (res != 0) {printf("等待线程失败\n");return 0;}if (mess == PTHREAD_CANCELED) {printf("myThread 线程被强制终止\n");}else {printf("error\n");}return 0;
}

假设程序编写在 thread.c 文件中,程序执行过程如下:

[root@localhost ~]# gcc thread.c -o thread.exe -lpthread
[root@localhost ~]# ./thread.exe
新建线程开始执行
myThread 线程被强制终止

上面是在linux上的执行结果,在Windows下的执行结果如下图


暂时还不知道是因为啥导致了这种结果,推测是因为运行环境不同,这边就先挖个坑,等后面了解了再来解决。

和《终止线程执行(3种方法)》一节中 pthread_cancel() 函数的演示程序相比,我们仅仅是将 myThread 线程设置为“接收到 Cancel 信号后立即结束执行”。通过对比两个程序的输出结果,很容易就可以体会出 pthread_setcancelstate() 和 pthread_setcanceltype() 函数的功能。

【多线程编程学习笔记6】终止线程执行,千万别踩这个坑!相关推荐

  1. 多线程编程学习笔记——线程池(二)

    接上文 多线程编程学习笔记--线程池(一) 三.线程池与并行度 此示例是学习如何应用线程池实现大量的操作,及与创建大量线程进行工作的区别. 1. 代码如下 using System; using Sy ...

  2. 多线程编程学习笔记——async和await(三)

    接上文 多线程编程学习笔记--async和await(一) 接上文 多线程编程学习笔记--async和await(二) 五.   处理异步操作中的异常 本示例学习如何在异步函数中处理异常,学习如何对多 ...

  3. 多线程编程学习笔记——任务并行库(二)

    接上文 多线程编程学习笔记--任务并行库(一) 三.   组合任务 本示例是学习如何设置相互依赖的任务.我们学习如何创建一个任务的子任务,这个子任务必须在父任务执行结束之后,再执行. 1,示例代码如下 ...

  4. Linux与C++11多线程编程(学习笔记)

    多线程编程与资源同步 在Windows下,主线程退出后,子线程也会被关闭; 在Linux下,主线程退出后,系统不会关闭子线程,这样就产生了僵尸进程 3.2.1创建线程 Linux 线程的创建 #inc ...

  5. 多线程编程学习笔记——使用并发集合(三)

    接上文 多线程编程学习笔记--使用并发集合(一) 接上文 多线程编程学习笔记--使用并发集合(二) 四.   使用ConcurrentBag创建一个可扩展的爬虫 本示例在多个独立的即可生产任务又可消费 ...

  6. 多线程编程学习笔记——任务并行库(三)

    接上文 多线程编程学习笔记--任务并行库(一) 接上文 多线程编程学习笔记--任务并行库(二) 六.   实现取消选项 本示例学习如何实现基于Task的异步操作进行取消流程,以及在任务真正运行前如何知 ...

  7. python3多线程编程_Python 3多线程编程学习笔记-基础篇

    本文是学习<Python核心编程>的学习笔记,介绍了Python中的全局解释器锁和常用的两个线程模块:thread, threading,并对比他们的优缺点和给出简单的列子. 全局解释器锁 ...

  8. Posix多线程编程学习笔记(二)—线程属性(3)

    六.线程的作用域 函数pthread_attr_setscope和pthread_attr_getscope分别用来设置和得到线程的作用域,这两个函数的定义如下: 7. 名称:: pthread_at ...

  9. 多线程编程学习笔记1时间

    时间 c语言如何处理时间 c语言如何处理时间:time.h long t0 = time(NULL) ;//获取unix时间(从1970年1月1日到当前时经过的秒数 sleep(3)://让程序休眠3 ...

最新文章

  1. powerdesigner 概念模型_“使用满足”分析框架下社交媒体用户持续使用行为的概念模型研究...
  2. 170828、Eclipse Java注释模板设置详解以及版权声明
  3. java.lang.UnsatisfiedLinkError: com.jacob.com.D...
  4. Android WebView 在内部打开链接,捕获错误
  5. java spr_Java中的42行代码中的URL缩短器服务(Java(?!)Spring Boot + Redis
  6. fanuc机器人刷机教程_发那科机器人的正确操作方法及步骤
  7. 如何在ROS环境中解码.bag格式数据
  8. C++ 泛型编程-模板
  9. 我的世界服务器如何开无限小号,实操神技能,微信能“无限”开小号?
  10. 确定空间直线延长线上的一点
  11. 前端食堂技术周刊第 40 期:HTTP/3、WebContainers 登陆 Firefox、Remix Conf 2022、VueConf US 2022
  12. 武大三行情书第一名---《螃蟹在剥我的壳》
  13. php携程源码,Swoole2.0协程的使用和源码解读
  14. @所有人:产品汪、运营喵专属台历,你值得拥有!
  15. 液晶如何显示变量的内容
  16. 听说你想进大厂?当心这13个MySQL送命题!
  17. Laravel 5.4设置logout注销账户的重定向路径
  18. vim 查找替换操作命令
  19. 一对一 视频聊天源码,不要小瞧社交平台的盈利方式
  20. ibatis遍历数组出错

热门文章

  1. 童文、李烨:6G的9大挑战
  2. “Elasticsearch + Kibana + ik分词器“介绍与使用
  3. 计算机毕业设计 Java web物流配送管理系统
  4. 图解B+树并和B-树特点对比总结
  5. 传输层 TCP UPD 应用场景
  6. 网站风格变黑白的方法,用css或javascript方法将网站改为灰色
  7. vue cli 接入 mock
  8. 写一个Singleton模式的例子
  9. IT审计 独立于IT管理的监督过程(zt)
  10. N行M列每个位置放Aij个1厘米的正方体,求表面积