「这是我参与11月更文挑战的第 4 天,活动详情查看:2021最后一次更文挑战」。
参加该活动的第 7 篇文章
std::barrier
std::barrier 与 std::latch 非常相似。细微的区别在于,您可以多次使用 std::barrier,因为计数器将被重置为以前的值。在计数器变为零后,所谓的完成阶段立即开始。这个完成阶段是在 std::barrier 为空的情况下进行的。这在 std::flex_barrier 中有所改变。std::barrier 有两个有趣的方法 —— std::arrive_and_wait 和 std::arrive_and_drop 。当 std::arrive_and_wait 在同步点等待时,std::arrive_and_drop 将自己从同步机制中删除。
在详细介绍 std::flex_barrier 和完成阶段之前,我将给出一个简短的 std::barrier 示例。
第 6 行中的 std::barrier barrier 用于协调若干次执行任务的一系列线程。线程的数量是 n_threads (第 3 行)。每个线程通过 task.get() 获取它的任务(第 12 行),执行它并等待,直到它完成了它的任务(第 15 行) —— 直到所有线程都完成了它们的任务。
std::flex_barrier
在我看来,示例中的 std::flex_barrier 的名称有点令人困惑。例如,std::flex_barrier 被称为 notifying_barrier 。
std::flex_barrier 与 std::barrier 不同,它有一个额外的构造函数。此构造函数可以由将在完成阶段调用的可调用单元进行参数化。可调用单元必须返回一个数字。这个数字在完成阶段设置了计数器的值。数值为 -1 意味着计数器在下一个迭代中保持不变。不允许小于 -1 的数。
在完成阶段发生了什么 ?
- 所有线程都被阻塞。
- 线程被解除阻塞并执行可调用单元。
- 如果完成阶段结束,所有线程将被解除阻塞。
代码片段显示了 std::flex_barrier 的用法。
该示例采用与 std::barrier 示例类似的策略。不同之处在于,这一次 std::flex_barrier 的计数器在运行时进行了调整; 因此,第 11 行中的 std::flex_barrier task_barrier 获得了一个 lambda 函数。这个 lambda 函数通过引用捕获它的变量 current_thread 。变量将在第 21 行递减,如果线程完成了它的任务,active 将被设置为 false ; 因此,计数器在完成阶段减少。
与 std::barrier 和 std::latch 相比,flex_barrier 有一个特性。这是唯一一个你可以增加计数器的 屏障。