Rust スレッド間の通信 channel, send, recv
概要
- 別のスレッドにデータを送受信するには channel を使う。
- データを送信するには send を使う。
- データを受信するには recv を使う。
プログラム例
- 1から50までの和をスレッド1で計算する。
- 51から100までの和をスレッド2で計算する。
- 本スレッドでそれらの合計を表示する。
use std::thread::{spawn}; use std::sync::mpsc::{channel}; fn main() { let (送信機1, 受信機) = channel(); let 送信機2 = 送信機1.clone(); spawn(move || { 送信機1.send(合計を求める(1, 50)).unwrap(); }); spawn(move || { 送信機2.send(合計を求める(51, 100)).unwrap(); }); let 結果1 = 受信機.recv().unwrap(); let 結果2 = 受信機.recv().unwrap(); println!("{}", 結果1 + 結果2); } fn 合計を求める(開始: i32, 終了: i32) -> i32 { (開始..=終了).fold(0, |sum, i| sum + i) }
解説
fn main() { let (送信機1, 受信機) = channel(); // └ スレッド間の通信に使える送信機と受信機のセットが得られる。 let 送信機2 = 送信機1.clone(); // └ 送信機はコピーできる。 spawn(move || { // └ move ◁「受信機1」をスレッド内で使えるようにする。 送信機1.send(合計を求める(1, 50)).unwrap(); // └ スレッド1からは、1から50の合計を送信する(エラー処理を省略)。 }); spawn(move || { 送信機2.send(合計を求める(51, 100)).unwrap(); // └ スレッド2からは、51から100の合計を送信する(エラー処理を省略)。 }); let 結果1 = 受信機.recv().unwrap(); let 結果2 = 受信機.recv().unwrap(); // └ 2回受信するまで待ち続ける(エラー処理を省略)。 println!("{}", 結果1 + 結果2); }
補足
- join() でデータを受け取れるのは一回きりだが、recv() では何回でも受け取れる。
- send() でエラーになるのは、相手のスレッドがすでに終了している場合。
- recv() でエラーになるのは、受信機に対応する送信機がすべて破棄されていた場合。
- 受信機が生きている間は、recv() すると無限待ち状態になるので注意。
- 受信に時間制限を設けるには recv_timeout(Duration::from_secs(1)) のようにする。
- タイムアウト時はエラーが発生するので match で処理する。