Files
CPlusPlusThings/site_extras/modern-cpp-cpp20-cpp20-channel.md
light-city dfe1c933b3 docs: address community issue feedback (#5 #338 #142 #246 #136 #303)
- const README: rewrite the space-saving claim per issue #5 follow-ups
  (constant-expression const vs #define immediates; which const qualify
  as constant expressions)
- const README: fix the class-section diagnosis per issue #338 (overload
  resolution picks the const overload; the restriction only surfaces
  once that overload is removed)
- sizeof README: virtual-inheritance result is compiler-dependent
  (GCC merges vbptr+vfptr -> 16, MSVC keeps them separate -> 32) #246
- static README: new section on internal linkage / access restriction
  with anonymous-namespace comparison #142
- 10-day practice: full problem list table + fixed day links #136
- new design_pattern/singleton/singleton_default.hpp: reusable
  thread-safe CRTP singleton template, compile+concurrency tested #303
2026-10-13 19:23:54 +08:00

112 lines
2.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
> 来自 [C++那些事网站](https://light-city.github.io/stories_things/modern-cpp/cpp20/cpp20-channel/) 的文章,由站点同步脚本导出。
# C++20 channel 实战
## C++20实战之channel
继前面两节的直播,讲解了thread、jthread、stop_token、stop_source、stop_callback、cv、cv_any等的用法与底层实现,那么如何基于这些知识实现一个小项目呢?
于是引出了这篇,写一个channel出来。
## 1.设计
### 1.1 接口设计
接口层面我们期望与通用的channel一样,能够一次性创建一个发送、接收的channel。
例如:
```cpp
auto [sender, receiver] = make_channel<int>();
```
这里的实现可以通过类似make_unique提供一个对外的接口,返回值通过C++17的结构化绑定获取,此时便得到了两个channel。
最核心的两个接口:发送与接收。
- 发送
```cpp
sender.send(counter++);
```
- 接收
```
auto value = receiver.recv();
```
除此之外,还可以在析构函数的时候提供一个shutdown接口,当send、recv阻塞的时候能够被唤醒释放。
例如:
```cpp
bool shutdown() {
if (!state_) {
return false;
}
light_city_lock lk(state_->mutex);
if (source_.stop_requested()) {
return false;
}
source_.request_stop();
state_->cv.notify_all();
return true;
}
```
### 1.2 内部队列设计
内部队列可以参考前面几天发的如何设计一个线程安全的多生产者多消费者队列,这里可以内部维护一个state,然后带上queue、mutex、cv_any。
```cpp
struct State {
std::queue<T> queue;
std::mutex mutex;
// C++11 condition_variable_any
std::condition_variable_any cv;
};
```
## 2.使用
使用起来就非常容易,只需要make出来两个channel,然后去send与recv即可。
这里我使用了jthread + stop_token来完成这个工作,例如:
```cpp
std::jthread sender_thread(
[](Channel<int> sender, std::stop_token token) {
int counter = 0;
while (!token.stop_requested()) {
sender.send(counter++);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
},
std::move(sender), token);
```
接收端线程类似,在执行的差不多时,我们可以使用
```
stop_source.request_stop();
```
至此,便模拟了一个channel,发送端发送数据,接收端接收数据即可。
运行示例:
```cpp
➜ channel ./a.out
Received: 0
Received: 1
Received: 2
Received: 3
Received: 4
Received: 5
Received: 6
Received: 7
Received: 8
Received: 9
```