Última atualização:2026-10-12
Prática com channel no C++20¶
Prática do C++20: channel¶
Após as duas lives anteriores, que explicaram o uso e a implementação subjacente de thread, jthread, stop_token, stop_source, stop_callback, cv, cv_any, etc., como construir um pequeno projeto com base nesses conhecimentos?
Daí nasceu este artigo: escrever um channel.
1.Design¶
1.1 Design da interface¶
No nível da interface, esperamos que seja como um channel de uso geral, capaz de criar de uma só vez um channel de envio e um de recebimento.
Por exemplo:
A implementação aqui pode fornecer uma interface externa semelhante a make_unique, e o valor de retorno é obtido por meio das vinculações estruturadas do C++17; assim, obtemos dois channels.
As duas interfaces mais centrais: envio e recebimento.
- Envio
- Recebimento
Além disso, podemos fornecer uma interface shutdown no destrutor, para que send e recv bloqueados possam ser despertados e liberados.
Por exemplo:
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 Design da fila interna¶
Para a fila interna, podemos nos referir ao artigo publicado há alguns dias sobre como desenhar uma fila thread-safe com múltiplos produtores e múltiplos consumidores; aqui podemos manter internamente um state, acompanhado de queue, mutex e cv_any.
struct State {
std::queue<T> queue;
std::mutex mutex;
// C++11 condition_variable_any
std::condition_variable_any cv;
};
2.Uso¶
O uso é bem fácil: basta fazer (make) dois channels e, então, enviar com send e receber com recv.
Aqui usei jthread + stop_token para realizar esse trabalho, por exemplo:
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);
A thread receptora é semelhante; quando a execução estiver quase no fim, podemos usar
Com isso, simulamos um channel: o lado que envia transmite os dados e o lado que recebe os obtém.
Exemplo de execução:
➜ channel ./a.out
Received: 0
Received: 1
Received: 2
Received: 3
Received: 4
Received: 5
Received: 6
Received: 7
Received: 8
Received: 9
Tópicos relacionados¶
- Introdução às corrotinas no C++20 | C++那些事
- Concepts (conceitos) no C++20 | C++那些事
- constexpr e a expressão vírgula no C++20 | C++那些事
- Ordem de bytes (endian) no C++20 | C++那些事
- Expressões Lambda no C++20 (parte 1) | C++那些事
- Módulos (Modules) no C++20 | C++那些事
- Biblioteca Ranges do C++20 | C++那些事
- Design e armadilhas do std::span no C++20 | C++那些事
- Guia dos novos recursos do C++20 | C++那些事
- [[likely]] e [[unlikely]] no C++20 | C++那些事