にっき

技術的な話題はないです

C++11で Rust の channelを実装してみる

とあるツールを作る際に非同期処理を実装したくなったのだが, その際に Rust にある channel があると便利そうだなぁと思ったので実装してみた.

概要

実装は この記事 を参考にした. ただし,Golang 版では双方向通信が可能になっているのに対し,移植版は一方向にするため Proxy sender<T>, receiver<T> を介して通信をするようにしている.

詳細

channel<T>

「要はスレッドセーフなキューにすればよいのだろう」というノリで,std::queue<T>ミューテックスと条件変数を付属させたものにした. 今のところブロッキング版のみだが,より使い勝手を良くしようと思ったらノンブロッキング版も用意する必要がある.

sender<T>

channel<T>のうち,send()のみを呼び出せるようにしたProxyオブジェクト. T が default constructible であれば送信時の値を省略できるようにした.

receiver<T>

channel<T>のうち,recv() のみを呼び出せるようにしたProxyオブジェクト. 受信側が複数存在するのを防ぐため non-copyable かつ movable にしている.

使い方

基本的には Rust の std::sync::mpsc::channel と同じように使える. 本家と比べると機能が不足しているため,実際に使う際にはもう少し改良が必要だろうけど.

sender<bool> tx;
receiver<bool> rx;
std::tie(tx, rx) = make_channel<bool>();

一つ注意点として,receiver<T> が non-copyable なため以下のように書かないとうまくいかない.

auto ch = make_channel<bool>();
auto tx = std::get<0>(ch);
auto rx = std::get<1>(std::move(ch));