| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> C++知识库 -> C++11实现一个cyclic barrier -> 正文阅读 |
|
[C++知识库]C++11实现一个cyclic barrier |
在上文中使用计数器作为同步事件实现了latch,其实在多线程并发编程实践中,还有一种使用计数器作为同步事件的机制:Cyclic-Barrier,即循环屏障的意思。它指定了参与执行线程的数量,当某个线程运行到指定位置时就处于等待状态,只有当这些线程全部都到达该位置时,它们才能一起从等待状态中退出。它的实现原理也是以一个计数器作为同步变量,当某个线程到达指定的位置时,就让计数器的值减少1,如果结果不为0时,线程就进入等待状态,只有当计数器减到0时,即指定数量的线程全部到达了指定位置,此时所有在该位置等待的线程全部被唤醒,然后执行各自后续的流程。 下面是cyclic_barrier类的定义:
既然线程有需要等待唤醒、通知的机制,使用互斥量m和条件变量cv就是不二之选了,使用它们进行线程的等待和唤醒操作。 看一下各个成员函数的实现。
构造函数有两个,如果不需要回调函数的话,可以使用第一个构造函数来创建对象,它指定了一个缺省实现的回调函数。 如果有自定义的回调函数,可以使用第二个构造函数来创建对象。参数n来指定参与者线程的数量,该参数必须大于0,否则直接抛出异常,构造失败。 2、wait函数
每当有一个线程调用了wait(),就让count减1,并检查count是否为0, 如果不为0,说明还有别的线程没有到达,就进入等待状态;如果为0,说明这些线程全部到达,就先调用回调函数,然后唤醒其它所有等待中的线程。因为是循环barrier,在count为0时,重新设置为parties,等待下一轮的线程。 回调函数执行完之后再唤醒其它线程,这样,如果在回调函数中修改了共享变量,可以保证在其它线程唤醒之前修改完成,以保证共享变量的访问安全。 wait()函数不妨看作是一个屏障(barrier),线程到达此位置时,都不能越过它,只能处于等待状态,直到最后一个线程到达。既然是屏障,那么线程在wait()之前所做的操作,如果涉及到共享变量的话,它们对共享变量所作的修改,也就都happen-before这个屏障之前,从而当所有线程从wait()中唤醒后,进行后续操作时,如果访问这些共享变量,都是发生在这个屏障之后,从而保证了这些共享变量的整体happen-before语义。同样,当最后一个线程到达,调用回调函数也不会越过wait(),如果在回调函数中也有修改共享变量的操作,这个操作同样也happen-before于线程唤醒后的后续操作。 线程在等待过程中也可以被打断,也就是说,即使还没有规定数量的线程调用wait(),也可以强制中断它。程序中使用broken作为中断标记,中断后它被设置为true,线程被唤醒后,如果发现broken=true,则说明是被中断唤醒的,此时线程就抛出broken异常,通知调用者。 4、中断函数
如果想要提前中断barrier,通过设置中断标记broken为true,并唤醒全部处于等待中的线程即可,此时线程从wait()中被唤醒后会抛出broken_exception异常。
3、其它函数
get_waitings()用来查询处于等待中的线程个数,get_parties()用来查询参与者的线程数量,它们都是const成员函数。 与latch相比,它们有如下特点: 2、cyclic_barrier的计数器减少到0后,它会被复位,重新设置为初始化时的值,可以被循环使用;而latch是一个一次性的事件,当计数器变为0之后,就不再使用了。 3、使用cyclic_barrier的线程进入等待和唤醒都是同一个函数:wait(),线程在执行过程中调用它时,相当于在该函数的调用位置处设置了一个屏障点,先到达的线程会在屏障点等待后到达的,只有在所有线程全部到达这个屏障点之后,它们才能同时越过这个屏障点;而latch一般是由两种不同性质的线程相互协作,使用了等待和通知机制,一种统一在某个位置等待(调用wait()),另一种通过检查计数器为0时来通知唤醒(调用countdown())。 4、cyclic_barrier有回调函数,在唤醒所有线程之前,可以执行这个回调函数。 示例:
barrier和latch都使用了计数器倒计数进行统计,它们的应用场景不太一样,为了便于区分它们,举两个生活中例子,可以体会一下它们的区别。 如果换成另一种场景,这几个基友约定谁先来谁先爬,假设风景区大门的门闩(Latch)上共有2把锁(latch的数量),钥匙分别由门卫和值班经理保管,第一个基友来的比较早,此时大门还没有开,那么他就只能等这2个掌管钥匙的人员来开门:门卫来上班了,把他掌管的那把锁打开(倒计数减1),基友继续等待;当值班经理上班后打开了第二把锁之后(倒计数为0),这个基友进入大门开始爬山(从等待中被唤醒)。此后,其它基友陆续到达后,就无需等待了,因为所有的锁都已经打开了,他们可以直接进入景区爬山。这是应用latch的场景。 C++20中提供了类似的功能,详见barrier类。 |
|
C++知识库 最新文章 |
【C++】友元、嵌套类、异常、RTTI、类型转换 |
通讯录的思路与实现(C语言) |
C++PrimerPlus 第七章 函数-C++的编程模块( |
Problem C: 算法9-9~9-12:平衡二叉树的基本 |
MSVC C++ UTF-8编程 |
C++进阶 多态原理 |
简单string类c++实现 |
我的年度总结 |
【C语言】以深厚地基筑伟岸高楼-基础篇(六 |
c语言常见错误合集 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 12:32:45- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |