C++20新特性的小细节,你掌握了吗?

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

[[428229]]

本文转载自微信公众号「程序喵大人」,作者程序喵大人。转载本文请联系程序喵大人公众号。

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

latch

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

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

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

  1. CountDownLatch::CountDownLatch(int32_t count) : count_(count) {} 
  2.  
  3. void CountDownLatch::CountDown() { 
  4.     std::unique_lock<std::mutex> lock(mutex_); 
  5.     --count_; 
  6.     if (count_ == 0) { 
  7.         cv_.notify_all(); 
  8.     } 
  9.  
  10. void CountDownLatch::Await(int32_t time_ms) { 
  11.     std::unique_lock<std::mutex> lock(mutex_); 
  12.     while (count_ > 0) { 
  13.         if (time_ms > 0) { 
  14.             cv_.wait_for(lock, std::chrono::milliseconds(time_ms)); 
  15.         } else { 
  16.             cv_.wait(lock); 
  17.         } 
  18.     } 
  19.  
  20. int32_t CountDownLatch::GetCount() const { 
  21.     std::unique_lock<std::mutex> lock(mutex_); 
  22.     return count_; 

barrier

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

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

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

  1. #include <barrier> 
  2. #include <iostream> 
  3. #include <string> 
  4. #include <thread> 
  5. #include <vector> 
  6.   
  7. int main() { 
  8.   const auto workers = { "anil""busara""carl" }; 
  9.   
  10.   auto on_completion = []() noexcept {  
  11.     // locking not needed here 
  12.     static auto phase = "... done\n" "Cleaning up...\n"
  13.     std::cout << phase; 
  14.     phase = "... done\n"
  15.   }; 
  16.   std::barrier sync_point(std::ssize(workers), on_completion); 
  17.   
  18.   auto work = [&](std::string name) { 
  19.     std::string product = "  " + name + " worked\n"
  20.     std::cout << product;  // ok, op<< call is atomic 
  21.     sync_point.arrive_and_wait(); 
  22.   
  23.     product = "  " + name + " cleaned\n"
  24.     std::cout << product; 
  25.     sync_point.arrive_and_wait(); 
  26.   }; 
  27.   
  28.   std::cout << "Starting...\n"
  29.   std::vector<std::thread> threads; 
  30.   for (auto const& worker : workers) { 
  31.     threads.emplace_back(work, worker); 
  32.   } 
  33.   for (auto& thread : threads) { 
  34.     thread.join(); 
  35.   } 

可能的输出如下:

  1. Starting... 
  2.   anil worked 
  3.   carl worked 
  4.   busara worked 
  5. ... done 
  6. Cleaning up... 
  7.   busara cleaned 
  8.   carl cleaned 
  9.   anil cleaned 
  10. ... done 

semaphore

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

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

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

示例代码如下:

  1. #include <iostream> 
  2. #include <thread> 
  3. #include <chrono> 
  4. #include <semaphore> 
  5.  
  6. std::binary_semaphore 
  7.   smphSignalMainToThread(0), 
  8.   smphSignalThreadToMain(0); 
  9.   
  10. void ThreadProc() {   
  11.   smphSignalMainToThread.acquire(); 
  12.   std::cout << "[thread] Got the signal\n"; // response message 
  13.   using namespace std::literals; 
  14.   std::this_thread::sleep_for(3s); 
  15.   
  16.   std::cout << "[thread] Send the signal\n"; // message 
  17.   smphSignalThreadToMain.release(); 
  18.   
  19. int main() { 
  20.   std::thread thrWorker(ThreadProc); 
  21.   std::cout << "[main] Send the signal\n"; // message 
  22.   
  23.   smphSignalMainToThread.release(); 
  24.   
  25.   smphSignalThreadToMain.acquire(); 
  26.   
  27.   std::cout << "[main] Got the signal\n"; // response message 
  28.   thrWorker.join(); 
  29. 输出如下: 
  30. [main] Send the signal 
  31. [thread] Got the signal 
  32. [thread] Send the signal 
  33. [main] Got the signal 

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

 

打完收工。

 

责任编辑:武晓燕 来源: 程序喵大人
相关推荐

2024-01-19 21:07:22

C++20Concepts函数

2020-01-10 15:44:50

编程语言C++Java

2024-02-05 22:13:50

C++C++20开发

2020-10-14 07:52:36

ES11编程语言开发

2023-11-04 20:00:02

C++20协程

2023-11-15 15:54:17

C++运算符

2010-08-04 15:01:00

2020-12-21 21:05:29

C++C++20标准草案

2014-02-17 10:54:13

PostgreSQL数据库

2024-08-13 08:30:13

2023-11-20 22:19:10

C++static

2021-03-05 18:38:45

ESvue项目

2024-10-21 07:05:14

C#特性语言

2024-05-17 08:42:52

AttributeMyClass方法

2020-02-03 13:55:49

技术研发指标

2023-08-08 08:08:42

PythonWeb开发

2013-06-09 16:26:56

Windows 8.1

2024-03-20 08:31:40

KotlinExtension计算

2024-07-12 15:46:58

2019-11-20 10:38:36

路由路由协议路由器
点赞
收藏

51CTO技术栈公众号