通常のスレッド
Rust のスレッドは、他の言語のスレッドと同様に動作します:
// Copyright 2024 Google LLC // SPDX-License-Identifier: Apache-2.0 use std::thread; use std::time::Duration; fn main() { thread::spawn(|| { for i in 0..10 { println!("Count in thread: {i}!"); thread::sleep(Duration::from_millis(5)); } }); for i in 0..5 { println!("Main thread: {i}"); thread::sleep(Duration::from_millis(5)); } }
- 新しいスレッドを生成しても、
mainの最後でプログラムの終了が自動的に 遅らされることはありません。 - スレッドの panic は互いに独立しています。
- panic はペイロードを持つことができ、その内容は
Any::downcast_refで取り出せます。
- panic はペイロードを持つことができ、その内容は
-
この例を実行します。
- 5ms というタイミングには十分な余裕があるため、main スレッドと生成した スレッドはほぼ足並みをそろえて進みます。
- 生成したスレッドが 10 に到達する前にプログラムが終了することに注目して ください。
- これは
mainがプログラムを終了させ、生成したスレッドはプログラムを 存続させないためです。- 必要であれば、
pthreads/C++std::thread/boost::threadと比較して みてください。
- 必要であれば、
-
生成したスレッドが完了するまで待つには、どうすればよいでしょうか。
-
thread::spawnはJoinHandleを返します。ドキュメントを見てください。JoinHandleには、ブロックする.join()メソッドがあります。
-
let handle = thread::spawn(...)とし、後でhandle.join()を使って スレッドの終了を待つと、プログラムは最後まで数えて 10 に到達します。 -
では、値を返したい場合はどうでしょうか。
-
もう一度ドキュメントを見てください:
thread::spawnのクロージャはTを返しますJoinHandleの.join()はthread::Result<T>を返します
-
handle.join()のResultの戻り値を使って、返された値にアクセスします。 -
では、もう一方のケースはどうでしょうか。
- スレッドで panic を発生させます。これによって
mainは panic しないことに 注目してください。 - panic のペイロードにアクセスします。ここで
Anyについて説明するのに ちょうどよいタイミングです。
- スレッドで panic を発生させます。これによって
-
これでスレッドから値を返せるようになりました。では、入力を受け取るには どうすればよいでしょうか。
- スレッドのクロージャで何かを参照としてキャプチャします。
- エラーメッセージは、それを move しなければならないことを示します。
- それを move すると、計算してから派生した値を返せることがわかります。
-
借用したい場合はどうでしょうか。
mainは戻るときに子スレッドを終了させますが、別の関数であれば単に 戻って、それらを実行したままにしてしまいます。- それはスタック use-after-return であり、メモリ安全性に違反します!
- これをどう避ければよいでしょうか。次のスライドを見てください。