C++ 多线程——pthread_cancel 取消线程的疑惑

测试环境:Ubuntu18.04

pthread_cancel 简介

pthread_cancel(threadID)会发送终止信号给thread线程,如果成功则返回0,否则为非0值。pthread_cancel调用并不等待线程终止,它只是向目标线程发Cancel信号, 提出取消请求。但目标线程如何处理Cancel信号则由目标线程自己决定,或者忽略(当禁止取消时)、或者立即终止(当在取消点或异步模式下)、或者继续运行至Cancelation-point(取消点,下面将描述),总之由不同的Cancelation状态决定。

示例代码

下面这个示例代码将开启两个子线程thread1 thread2

thread1 —> while死循环输出信息

thread2 —> 延时两秒 然后通过pthread_cancel来取消thread1线程

代码如下:

#include <iostream>
#include <unistd.h>
#include <pthread.h>void* thread1(void *arg)
{while (1){std::cout << "thread1 running" << std::endl;}std::cout << "Leave thread1!" << std::endl;return nullptr;
}void* thread2(void *arg)
{sleep(2);pthread_cancel(*static_cast<pthread_t*>(arg)); //取消线程std::cout << "send pthread_cancel!" << std::endl;return nullptr;
}int main(int argc, char** argv)
{// 启动子线程1 join运行pthread_t tid1;pthread_create(&tid1, nullptr, thread1, nullptr);// 启动子线程2 detach运行 计时两秒后 发送pthread_cancel 来结束 子线程1pthread_t tid2;pthread_create(&tid2, nullptr, thread2, &tid1);// pthread_detach()即主线程与子线程分离,两者相互不干涉,不会阻塞主线程,主线程结束同时子线程的资源自动回收pthread_detach(tid2);// pthread_join()即是子线程合入主线程,主线程会一直阻塞,直到子线程执行结束,然后回收子线程资源,并继续向下执行pthread_join(tid1, nullptr);// 上述代码  由于thread1 会阻塞主线程,所以程序会阻塞在这里无法继续执行。当成功取消thread1后会继续向下执行。这里用打印  "main thread!" 来查看 thread1 是否结束。std::cout << "main thread!" << std::endl;while (1) {sleep(1);}return 0;
}

运行结果

........
thread1 running
thread1 running
thread1 running
send pthread_cancel!

可以看到程序并没有打印 main thread! 说明 thread1 子线程并没有结束。

难道是因为 线程处于无限循环中,且循环体内没有执行至取消点的必然路径,则线程无法由外部其他线程的取消请求而终止?????

这种问题该怎么解决呢?

解决方法一 手动插入一个取消点

void* thread1(void *arg)
{while (1){std::cout << "thread1 running" << std::endl;/** 手动创建一个取消点 pthread_testcancel()* pthread_testcancel会检查本线程是否处于Canceld状态,如果是,则进行取消动作,否则直接返回。 * 此函数在线程内执行,执行的位置就是线程退出的位置,在执行此函数以前,线程内部的相关资源申请一定要释放掉,他很容易造成内存泄露。*/pthread_testcancel();}std::cout << "Leave thread1!" << std::endl;return nullptr;
}

运行结果

........
thread1 running
thread1 running
thread1 running
send pthread_cancel!
main thread!

可以看到thread1成功取消

解决方法二 sleep 延时

void* thread1(void *arg)
{while (1){std::cout << "thread1 running" << std::endl;/** usleep(1)  延时1微妙  也就是0.001毫秒*/usleep(1);}std::cout << "Leave thread1!" << std::endl;return nullptr;
}

运行结果

........
thread1 running
thread1 running
thread1 running
send pthread_cancel!
main thread!

哇哦,也成功了…

难道是while死循环中没有延时 导致cancel信号被忽略??? 还是因为 sleep 延时本身就算是一个取消点???

再改变一下log输出的方式

void* thread1(void *arg)
{while (1){// std::cout << "thread1 running" << std::endl;printf("thread1 running\n");}std::cout << "Leave thread1!" << std::endl;return nullptr;
}

运行结果

........
thread1 running
thread1 running
thread1 running
send pthread_cancel!
main thread!

这到底怎么回事??
只是简单的换了一下log的输出方式,就产生了不一样的结果。
作为小白,我也很疑惑…

pthread 的高级配置

设置本线程对Cancel信号的反应
int pthread_setcancelstate(int state, int *oldstate);
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* thread1(void *arg)
{pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); //允许退出线程pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); //设置立即取消while (1){std::cout << "thread1 running" << std::endl;}std::cout << "Leave thread1!" << std::endl;return nullptr;
}

运行结果

........
thread1 running
thread1 running
thread1 running
send pthread_cancel!

参考博文

https://www.cnblogs.com/lijunamneg/archive/2013/01/25/2877211.html

https://www.cnblogs.com/wangchaoguo-li/archive/2012/11/08/2760006.html

C++ 多线程——pthread_cancel 取消线程的疑惑相关推荐

  1. .NET异步和多线程系列(四)- 多线程异常处理、线程取消、多线程的临时变量问题、线程安全和锁lock

    本文是.NET异步和多线程系列第四章,主要介绍的是多线程异常处理.线程取消.多线程的临时变量问题.线程安全和锁lock等. 一.多线程异常处理 多线程里面抛出的异常,会终结当前线程,但是不会影响别的线 ...

  2. Linux多线程实践(2) --线程基本API

    POSIX线程库 与线程有关的函数构成了一个完整的系列,绝大多数函数的名字都是以"pthread_"开头,要使用这些函数库,要通过引入头文<pthread.h>,而且链 ...

  3. 多线程概念,线程控制

    文章目录 多线程 线程概念 多任务处理: 多线程/多进程进行多任务处理的优缺点分析 多线程的优点 多进程的优点 共同的优点 线程控制 线程的创建 线程的终止 线程的等待 线程的分离 多线程 线程概念 ...

  4. iOS多线程全套:线程生命周期,多线程的四种解决方案,线程安全问题,GCD的使用,NSOperation的使用(上)

    2017-07-08 remember17 Cocoa开发者社区 目的 本文主要是分享iOS多线程的相关内容,为了更系统的讲解,将分为以下7个方面来展开描述. 多线程的基本概念 线程的状态与生命周期 ...

  5. 细说C#多线程那些事 - 线程同步和多线程优先级

    上个文章分享了一些多线程的一些基础的知识,今天我们继续学习. 一.Task类 上次我们说了线程池,线程池的QueueUserWorkItem()方法发起一次异步的线程执行很简单 但是该方法最大的问题是 ...

  6. Java多线程系列--“JUC线程池”06之 Callable和Future

    转载自  Java多线程系列--"JUC线程池"06之 Callable和Future Callable 和 Future 简介 Callable 和 Future 是比较有趣的一 ...

  7. pthread_cancel 退出线程引起死锁的问题和解决方法

    Posix的线程终止有两种情况:正常终止和非正常终止.线程主动调用pthread_exit()或者从线程函数中return都将使线程正常退出,这是可预见的退出方式:非正常终止是线程在其他线程的干预下, ...

  8. linux取消线程的原理,linux线程的取消(终止)方法

    关键: pthread_cancel函数发送终止信号 pthread_setcancelstate函数设置终止方式 pthread_testcancel函数取消线程(另一功能是:设置取消点) 1 线程 ...

  9. C++多线程之间,线程函数启动之后,多线程依赖的启动和线程唤醒操作。

    C++多线程之间,线程函数启动之后,线程间依赖的启动和唤醒操作 一.原理分析 1. 线程依赖关系 二. 实例分析 2.1 多线程启动 2.2 多线程模式讲解 (1) 多线程开启与主线程唤醒 (2)单线 ...

最新文章

  1. mysql替换开头_如何在MySQL的字符串开头搜索和替换特定字符?
  2. PTA 1067 Sort with Swap(0, i) (25 分)(思维)
  3. oralce创建用户
  4. 移动端REM布局方案
  5. 前端、后端、全栈都要学什么?薪资前景如何?
  6. Github版本控制——基础操作
  7. 分布式服务防雪崩熔断器(Hystrix),实现服务降级
  8. x264编码详细文字全过程
  9. git 设置和取消代理
  10. 项目管理-项目整体计划Excel表格绘制
  11. 以太网驱动详解之 MAC、MII、PHY 详解
  12. Access数据库修复 压缩
  13. 读书笔记 | 4.3 基于征信系统的征信基础产品
  14. Google books deal battle heats up 谷歌数字图书馆建
  15. 华为hicar 鸿蒙,华为智能座舱的野心:HiCar上车,为鸿蒙OS铺路
  16. python3.4学习笔记(十八) pycharm 安装使用、注册码、显示行号和字体大小等常用设置...
  17. 会python_会Python了不起吗?是的,简直开挂!
  18. 内网穿透工具-venom
  19. 基于Smart200 PLC的运动控制组态说明
  20. 前端面试题 - 面试

热门文章

  1. 乖离率背离公式_股票bias指标使用技巧-股票bias指标的使用五大技巧 股票bias指标计算公式...
  2. oracle 客户端可以连接11g rac vip 但是不能连接scan ip问题
  3. thonny中文版|python编辑
  4. 结绳中文编程入门手册
  5. 微信小程序免费http转https
  6. 自己写一个PRISMA 让两张图片融合起来
  7. 51单片机开发入门(3)-IO口应用
  8. python自己做课程表_Python课程表II
  9. 财务人员怎么用python_财务人员有必要学习Python语言吗?
  10. 梦想帝王多开辅助?梦想帝王脚本兵种详解