站长网 语言 C++20新特性的小细节,你学会了吗?

C++20新特性的小细节,你学会了吗?

之前我整理过一篇C++20新特性的文章全网首发!!C++20新特性全在这一张图里了,里面提到过latch、barrier和semaphore,但是没有详细介绍过三者的作用和区别,这里详细介绍下。latch这个可能大多数人都有所了解,这就是我们经常会用到的CountDownLatch。用于使

之前我整理过一篇C++20新特性的文章全网首发!!C++20新特性全在这一张图里了,里面提到过latch、barrier和semaphore,但是没有详细介绍过三者的作用和区别,这里详细介绍下。

 

latch

这个可能大多数人都有所了解,这就是我们经常会用到的CountDownLatch。用于使一个线程先阻塞,等待其他线程完成各自的工作后再继续执行。

 

CountDownLatch是通过计数器实现,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后等待的线程就可以打断阻塞去继续执行任务。

 

自己之前实现过一个CountDownLatch,源码大概这样:

 

CountDownLatch::CountDownLatch(int32_t count) : count_(count) {} 

 

void CountDownLatch::CountDown() { 

    std::unique_lock<std::mutex> lock(mutex_); 

    –count_; 

    if (count_ == 0) { 

        cv_.notify_all(); 

    } 

 

void CountDownLatch::Await(int32_t time_ms) { 

    std::unique_lock<std::mutex> lock(mutex_); 

    while (count_ > 0) { 

        if (time_ms > 0) { 

            cv_.wait_for(lock, std::chrono::milliseconds(time_ms)); 

        } else { 

            cv_.wait(lock); 

        } 

    } 

 

int32_t CountDownLatch::GetCount() const { 

    std::unique_lock<std::mutex> lock(mutex_); 

    return count_; 

barrier

许多线程在阻塞点阻塞,当到达阻塞点的线程达到一定数量时,会执行完成的回调,然后解除所有相关线程的阻塞,然后重置线程计数器,继续开始下一阶段的阻塞。

 

假设有很多线程并发执行,并在一个循环中执行一些计算。进一步假设一旦这些计算完成,需要在线程开始其循环的新迭代之前对结果进行一些处理。

 

看以下示例代码(摘自cppreference):

 

#include <barrier> 

#include <iostream> 

#include <string> 

#include <thread> 

#include <vector> 

  

int main() { 

  const auto workers = { "anil", "busara", "carl" }; 

  

  auto on_completion = []() noexcept {  

    // locking not needed here 

    static auto phase = "… done\n" "Cleaning up…\n"; 

    std::cout << phase; 

    phase = "… done\n"; 

  }; 

  std::barrier sync_point(std::ssize(workers), on_completion); 

  

  auto work = [&](std::string name) { 

    std::string product = "  " + name + " worked\n"; 

    std::cout << product;  // ok, op<< call is atomic 

    sync_point.arrive_and_wait(); 

  

    product = "  " + name + " cleaned\n"; 

    std::cout << product; 

    sync_point.arrive_and_wait(); 

  }; 

  

  std::cout << "Starting…\n"; 

  std::vector<std::thread> threads; 

  for (auto const& worker : workers) { 

    threads.emplace_back(work, worker); 

  } 

  for (auto& thread : threads) { 

    thread.join(); 

  } 

可能的输出如下:

 

Starting… 

  anil worked 

  carl worked 

  busara worked 

… done 

Cleaning up… 

  busara cleaned 

  carl cleaned 

  anil cleaned 

… done 

semaphore

信号量,这个估计大家都很熟悉,本质也是个计数器,主要有两个方法:

 

acquire():递减计数器,当计数器为零时阻塞,直到计数器再次递增。

 

release():递增计数器(可传递具体数字),并解除在acquire调用中的线程的阻塞。

 

示例代码如下:

 

#include <iostream> 

#include <thread> 

#include <chrono> 

#include <semaphore> 

 

std::binary_semaphore 

  smphSignalMainToThread(0), 

  smphSignalThreadToMain(0); 

  

void ThreadProc() {   

  smphSignalMainToThread.acquire(); 

  std::cout << "[thread] Got the signal\n"; // response message 

  using namespace std::literals; 

  std::this_thread::sleep_for(3s); 

  

  std::cout << "[thread] Send the signal\n"; // message 

  smphSignalThreadToMain.release(); 

  

int main() { 

  std::thread thrWorker(ThreadProc); 

  std::cout << "[main] Send the signal\n"; // message 

  

  smphSignalMainToThread.release(); 

  

  smphSignalThreadToMain.acquire(); 

  

  std::cout << "[main] Got the signal\n"; // response message 

  thrWorker.join(); 

输出如下: 

[main] Send the signal 

[thread] Got the signal 

[thread] Send the signal 

[main] Got the signal 

信号量也可以当作条件变量使用,这个我估计大家应该知道怎么做。

 

打完收工。

本文来自网络,不代表站长网立场,转载请注明出处:https://www.tzzz.com.cn/html/biancheng/yuyan/2021/1104/20036.html

作者: dawei

【声明】:站长网内容转载自互联网,其相关言论仅代表作者个人观点绝非权威,不代表本站立场。如您发现内容存在版权问题,请提交相关链接至邮箱:bqsm@foxmail.com,我们将及时予以处理。
联系我们

联系我们

0577-28828765

在线咨询: QQ交谈

邮箱: xwei067@foxmail.com

工作时间:周一至周五,9:00-17:30,节假日休息

返回顶部