「実践Rustプログラミング入門」を参考に。
スレッド、並行処理系が気になったので実験。
p.85 スレッドを作る
Rustのスレッド間データ送受信方式は、
- 共有メモリ方式
- メッセージパッシング方式
の2種類の方式があります、とのこと。標準的である。
新規にプロジェクトを作る。
PS > cargo new thread
Created binary (application) `thread` package
main.rsをp.85に従い、書き換える。thread
は標準ライブラリ。spawn
の引数|| {body}
はクロージャ。
use std::thread;
fn main() {
thread::spawn(|| {
println!("Hello, world!");
});
}
PS thread> cargo run
Compiling thread v0.1.0 (\thread)
Finished dev [unoptimized + debuginfo] target(s) in 1.34s
Running `target\debug\thread.exe`
PS thread> cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.02s
Running `target\debug\thread.exe`
PS thread> cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.02s
Running `target\debug\thread.exe`
PS thread> cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.02s
Running `target\debug\thread.exe`
Hello, world!
何回か試すと、メッセージが出る。threadなので、println!が動作する前に、mainが終了してしまうことがある。
必ず表示させるためのコードは以下。
use std::thread;
fn main() {
let handle = thread::spawn(|| {
println!("Hello, world!");
});
dbg!(handle.join());
}
実行する。
PS thread> cargo run
Compiling thread v0.1.0 (thread)
warning: unused `std::result::Result` that must be used
--> src\main.rs:8:5
|
8 | dbg!(handle.join());
| ^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(unused_must_use)]` on by default
= note: this `Result` may be an `Err` variant, which should be handled
= note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
warning: 1 warning emitted
Finished dev [unoptimized + debuginfo] target(s) in 1.14s
Running `target\debug\thread.exe`
Hello, world!
[src\main.rs:8] handle.join() = Ok(
(),
)
「Resultをきちんと使いなさい」と警告が出るが、実行はされる(p.86)。
きちんと使うと以下の通り。使わないことが分かっている変数は_code
のように_
から始まる変数名にする。
use std::thread;
fn main() {
let handle = thread::spawn(|| {
println!("Hello, world!");
});
match handle.join() {
Ok(_code) => println!("OK"),
Err(_err) => println!("Err"),
};
}
実行する。
PS thread> cargo run
Compiling thread v0.1.0 (thread)
Finished dev [unoptimized + debuginfo] target(s) in 0.82s
Running `target\debug\thread.exe`
Hello, world!
OK
想定通りの実行結果となる。
クロージャと言えば自由変数。と思ったら書籍にも記述されていた(pp.86-87)。
use std::thread;
fn main() {
let mut handles = Vec::new();
for x in 0..10 {
handles.push(thread::spawn(|| {
println!("Hello, world! {}", x);
}));
}
for handle in handles {
match handle.join() {
Ok(_code) => println!("OK"),
Err(_err) => println!("Err"),
};
}
}
PS thread> cargo run
Compiling thread v0.1.0 (thread)
error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function
--> src\main.rs:7:36
|
7 | handles.push(thread::spawn(|| {
| ^^ may outlive borrowed value `x`
8 | println!("Hello, world! {}", x);
| - `x` is borrowed here
|
note: function requires argument type to outlive `'static`
--> src\main.rs:7:22
|
7 | handles.push(thread::spawn(|| {
| ______________________^
8 | | println!("Hello, world! {}", x);
9 | | }));
| |__________^
help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword
|
7 | handles.push(thread::spawn(move || {
| ^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0373`.
error: could not compile `thread`.
To learn more, run the command again with --verbose.
cargo run
でもエラー。この辺りは動的言語のように緩く対応してくれない(システムプログラミング言語なので、適当に対応されると困る)。
p.87にもあるが、エラーメッセージ内でも「moveキーワードを使え」となっているので追記する。
use std::thread;
fn main() {
let mut handles = Vec::new();
for x in 0..10 {
handles.push(thread::spawn(move || {
println!("Hello, world! {}", x);
}));
}
for handle in handles {
match handle.join() {
Ok(_code) => println!("OK"),
Err(_err) => println!("Err"),
};
}
}
実行する。終了部分をいじってあるので、p.88とは出力が違っている(OKが出ている)。
PS thread> cargo run
Compiling thread v0.1.0 (thread)
Finished dev [unoptimized + debuginfo] target(s) in 1.00s
Running `target\debug\thread.exe`
Hello, world! 0
Hello, world! 1
Hello, world! 2
Hello, world! 3
Hello, world! 4
Hello, world! 5
Hello, world! 6
Hello, world! 7
Hello, world! 8
Hello, world! 9
OK
OK
OK
OK
OK
OK
OK
OK
OK
OK
良い感じ。
振り返り
スレッドプログラミングがこんなにあっさりとできる。pthreadができる前からプログラミングしていた世代には感動的なのではないか(pthreadができたのは1995年とのこと)。