Rust学習記録 -> スレッド間のチャネル通信


序文

スレッドの研究を終えた後、著者は、チャネルを使用してさまざまな種類のマルチスレッド間の通信を実現するマルチスレッド通信のツール、つまりチャネルについて学び続けました。これは、著者の次のような思考のきっかけにもなりました。語る。
同じ学習ビデオのアドレスは ->> B ステーション Linghu Yichong Rust Advanced


1. パイプラインとは何ですか?

Rust でメッセージ パッシングの同時実行を実装するための主要なツールの 1 つはチャネルです。チャネルは 2 つの部分で構成され、1 つは送信側、もう 1 つは受信側であり、送信側はメッセージの送信に使用され、受信側はメッセージの受信に使用されます。送信者または受信者のいずれかがドロップされると、チャネルは閉じられたとみなされます。

2. 利用手順

1.チャンネルの種類

1. mpsc::channel() を使用してチャネルを作成します。mpsc は複数のプロデューサーと 1 つのコンシューマーです。
2. SPMC::channel() を使用してチャネルを作成します。spmc は 1 つのプロデューサーと複数のコンシューマーです。

注: チャネルが作成されると、送信者と受信者 (プロデューサーとコンシューマー) が返されます。例:

let (tx,rx) = mpsc::channel();
let (tx,rx) = spmc::channel();

以下では、複数のプロデューサーと単一のコンシューマーを主な例として使用します。

2. チャネルの定義と使用

コードは以下のように表示されます。

use std::thread;
use std::sync::mpsc;

fn main() {
    
    
    let (tx, rx) = mpsc::channel();

    thread::spawn(move || {
    
    
        let val = String::from("hello,thread!");
        tx.send(val).unwrap();
    });

    let received = rx.recv().unwrap();
    println!("Main thread got {}",received);
}

上記のコードセグメントでは、作成者は mpsc::channel() を通じて (tx, rx)、つまり送信側と受信側を定義し、同時にサブスレッドを作成し、String 型の変数を定義しました。送信側は変数をチャネルに送信し、メインスレッドで定義された受信側 rx はチャネルで変数を受信し、最終的に出力します。コンパイルと実行の結果は次のとおりです。

root@ThinkPad-T540p:~/learn_rust/learn_thread_channel# cargo run
   Compiling learn_thread_channel v0.1.0 (/root/learn_rust/learn_thread_channel)
    Finished dev [unoptimized + debuginfo] target(s) in 0.82s
     Running `target/debug/learn_thread_channel`
Main thread got hello,thread!

コンパイルも実行もスムーズに進み、メインスレッドとサブスレッド間の通信も実現できましたが、前回のスレッド記事で、メインスレッドの影響でサブスレッドが強制的に中断されてしまうという事態に遭遇したことがありました。当時、この問題を解決するために join() が使用されましたが、ここでは join() は使用されず、メインスレッドはサブスレッドが val 変数を送信するのを待ち続けました。昨日学んだ知識。

この質問については、受信側の rx が使用するrecv()関数により、ビデオでも答えが得られます。ここで使用される recv() メソッドは、メッセージが到着して受信されるまでメイン スレッドをブロックしたままにするため、上記のコード セグメントでは join() メソッドは必要ありません。また、try_recv() メソッドも使用できます。ブロック、すぐに返されます。

3. チャネルの所有権の問題

上記のチャネル通信を簡単に利用するためのコード部分では、作成者は送信側チャネルへの送信データとして文字列変数 val を送信していますが、このとき val の所有権をチャネルに移すことと同じなので、チャネルが val を送信した後、 、val を単独で使用することはできなくなりました。

4. 多情報マルチスレッドシミュレーション

上記の検討を完了した後、単純な通信の実装に加えて、単一のサブスレッドで複数のメッセージを送信する状況や、複数のスレッドでメッセージを送信する状況も実装されます。

use std::thread;
use std::sync::mpsc;
use std::time::Duration;

fn main() {
    
    
    let (tx,rx) = mpsc::channel();

    thread::spawn(move || {
    
    
        let vals = vec![
            String::from("Hello"),
            String::from("nice"),
            String::from("to"),
            String::from("meet"),
            String::from("you!"),
        ];

        for val in vals {
    
    
            tx.send(val).unwrap();
            thread::sleep(Duration::from_secs(1));
        }
    });

    for recv in rx {
    
    
        println!("{}",recv);
    }
    println!("Hello, world!");
}

上記のコードは vec コンテナーを使用し、単一のサブスレッドで複数のメッセージをメインスレッドに送信します。コンパイルと実行結果は次のとおりです。

root@ThinkPad-T540p:~/learn_rust/learn_thread_channel3# cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.06s
     Running `target/debug/learn_thread_channel3`
Hello
nice
to
meet
you!
Hello, world!

同様に、複数のスレッドを実装する場合、コードは次のようになります。

use std::thread;
use std::sync::mpsc;
use std::time::Duration;

fn main() {
    
    
    let (tx, rx) = mpsc::channel();
    let tx1 = mpsc::Sender::clone(&tx);
    let tx2 = mpsc::Sender::clone(&tx);
    thread::spawn(move || {
    
    
        let vals = vec![
            String::from("1"),
            String::from("2"),
            String::from("3"),
            String::from("4"),
        ];
        for val in vals {
    
    
            tx.send(val).unwrap();
            thread::sleep(Duration::from_secs(1));
        }
    });

    thread::spawn(move || {
    
    
        let vals = vec![
            String::from("a"),
            String::from("b"),
            String::from("c"),
            String::from("d"),
        ];
        for val in vals {
    
    
            tx1.send(val).unwrap();
            thread::sleep(Duration::from_secs(1));
        }
    });

    thread::spawn(move || {
    
    
            let vals = vec![
            String::from("A"),
            String::from("B"),
            String::from("C"),
            String::from("D"),
        ];
        for val in vals {
    
    
            tx2.send(val).unwrap();
            thread::sleep(Duration::from_secs(1));
        }
    });

    for recv in rx {
    
    
        println!("{}",recv);
    }
    println!("Hello, world!");
}

コンパイルと実行結果は次のとおりです。

root@ThinkPad-T540p:~/learn_rust/learn_thread_channel4# cargo run
   Compiling learn_thread_channel4 v0.1.0 (/root/learn_rust/learn_thread_channel4)
    Finished dev [unoptimized + debuginfo] target(s) in 1.74s
     Running `target/debug/learn_thread_channel4`
1
a
A
b
2
B
3
c
C
d
4
D
Hello, world!

複数のスレッドによって送信された情報がメインスレッドによって順番に受信されることがわかります。


要約する

上記は私のチャネル学習の全プロセスですが、最近、スレッド間の循環コミュニケーションと返信の小さな例を書きました。完成したら参考として記事に追加します。読者の皆様も、私を啓発し、批判し、正していただくようお願いします。

おすすめ

転載: blog.csdn.net/weixin_45704680/article/details/121131377