RCIE-ジャンクのコード屋

主に自分のためにコーディングのTIPSを蓄積しています。

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)) のようにする。