话《C++》第12章并发,Page551 12.3.3线程剥离① 基本概念

基本概念:

两个概念:“线程”和“线程对象”。学习GUI时,提到过“窗口”和“窗口对象”之间的差别。

std::thread提供线程剥离(detach)方法,用于接触线程对象和实际线程之间的关系。为了见证detach()的强大破坏力,需要做一些对此。先看没有解除关系时的行为:

主线程对线程对象trd做了两件事:取它的ID,然后等待汇合。

【小提示】:关于线程ID

线程ID就是线程的编号。this_thread::get_id()取得当前所在线程ID。调用指定线程对象的get_id()则取得其对应的实际线程的ID。关于线程ID,唯一可确定的是:同一进程中同时存活的任意两个线程对象的ID,必不相同

其他的如:ID长什么样?是数字还是字符串?如果是数字采用什么进制?一个线程对象生命周期结束之后,它的ID会不会给新的线程对象复用等,都不确定。

线程ID的类型是std::thred::id,标准卡为该类型重载了“<<”操作符,以方便输出,同时也提供相等、不等和大小比较等操作。

运行上述例子,屏幕将输出trd线程的ID,大约5s后,程序优雅地退出。

接下来,我们将剥离trd对象和它所代表的实际线程后,然后再尝试通过get_id()方法,取线程ID,实际改动只是增加一行代码:28行,

取到ID了吗?不知道,因为程序崩溃了。

问题不在get_id(),而是join()的调用。detach()是剥离,是分手,join()是汇合,是牵手。

对比结论就是:调用过detach()的线程对象,就不允许再尝试join()。具体技术过程是,一旦“犯贱想重来”,程序就会抛出异常,如果不捕获,程序自然挂掉。

detach()是一个不可逆操作,分就分了,永无复合。上面的例子还用joinable()测试了执行过detach()操作的线程对象。

不过当务之急是验证get_id()这么简单的操作也失效了吗

下面用代码用休眠操作代替会坏事的汇合操作

屏幕输出内容是:

thread::id of a non-executing thread

这其实是线程ID所属类型std::thread::id在没有绑定实际线程时,默认构造的值。这显然是一句错误提示,谁会相信会有线程的ID长这个样子?

说“没有绑定实际线程”也不太准确,因为我们知道trd曾经拥有一个实际线程,只是没能走到白头,半路detach()掉了。

如果实际线程比线程对象先走一步,那么二者是不是也算是“分手”呢

主线程休眠1s, 但这1s里,trd对应的实际线程肯定必定一定完成任务了,并且挥手和trd告别,不复存在。1s之后,孤独而不知情的trd先是访问了线程ID,成功了,然后它在尝试合并线程,也成功了!怎么解释这一切?

正确答案是:这是“程序员友好”的设计,或者叫“接口友好”的设计。如果一个对象能不能调用某个方法,和某个实际线程是否还在运行有关,那么程序员可就惨了, 要么成天在掐指计算时间,要么就在代码中设置各种标志了。

在当前的代码里设置标志:

当前小节的结论:除非明明白白地调用detach(),否则,线程对象和线程之间的关系就是永恒的

至于调用trd.join()等待一个已经不复存在的线程,背后到底发生了什么?

  • 18
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值