安全性、速度、並行性を兼ね備えた言語と、巷でうわさのRustを覗いてみる(スレッド編 その2)
みなさまお久しぶりです。
今回も「The Rust Programming Language」を読みながら、スレッドについて見ていきたいと思います。
前回の「前回のスレッド編 その1」はこちらからご覧いただけます。
スレッドに名前をつけてみる
前回の最後のエラーで、スレッドがunnamedになっていましたが、どうやらスレッドに名前をつけれるようなので試してみます。
thread '<unnamed>' panicked at src/main.rs:10:17:
スレッドでエラーが発生しました
stack backtrace:
0: rust_begin_unwind
at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/std/src/panicking.rs:595:5
1: core::panicking::panic_fmt
at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/core/src/panicking.rs:67:14
2: *****::main::{{closure}}
at ./src/main.rs:10:17
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
スレッド: 0
スレッド: 1
スレッド: 2
スレッド: 3
スレッド: 4
スレッドでエラーが発生しました: Any { .. }
Process finished with exit code 0
thred::spawn
は内部的にはthread::Builder
を使っているようです。そしてBuilderを使うと名前をつけれるようです。
use std::thread;
use std::time::Duration;
fn main() {
let builder = thread::Builder::new().name("スレッ丼".into());
let handle = builder.spawn(|| {
for i in 0..10 {
if i == 5 {
// エラーを示すためにpanicを起こす
panic!("スレッドでエラーが発生しました");
}
println!("スレッド: {}", i);
thread::sleep(Duration::from_millis(1));
}
}).unwrap();
match handle.join() {
Ok(_) => println!("スレッドが正常に終了しました"),
Err(e) => println!("スレッドでエラーが発生しました: {:?}", e),
}
}
注意点としては、builder.spawn
はio::Result<JoinHandle<T>>
を返すことです。
とりあえず動作確認したいだけなので、unwrapをつけて処理しておきます。
thread 'スレッ丼' panicked at src/main.rs:12:17:
スレッドでエラーが発生しました
stack backtrace:
スレッド: 0
スレッド: 1
スレッド: 2
スレッド: 3
スレッド: 4
スレッドでエラーが発生しました: Any { .. }
0: rust_begin_unwind
at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/std/src/panicking.rs:595:5
1: core::panicking::panic_fmt
at /rustc/cc66ad468955717ab92600c770da8c1601a4ff33/library/core/src/panicking.rs:67:14
2: *****::main::{{closure}}
at ./src/main.rs:12:17
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
Process finished with exit code 0
無事、ふざけた名前のスレッド名が表示されました。
thread.current
を使うと、スレッド内から名前を参照できるらしいので試してみたいと思います。
use std::thread;
use std::time::Duration;
fn main() {
let builder = thread::Builder::new().name("スレッ丼".into());
let handle = builder.spawn(|| {
let handle = thread::current();
println!("スレッド名: {}", handle.name().unwrap());
thread::sleep(Duration::from_millis(1));
}).unwrap();
match handle.join() {
Ok(_) => println!("スレッドが正常に終了しました"),
Err(e) => println!("スレッドでエラーが発生しました: {:?}", e),
}
}
スレッド名: スレッ丼
スレッドが正常に終了しました
Process finished with exit code 0
問題なく取得できました。
スレッドのスタックサイズを設定してみる
おなじく、thread::Builder
を使うことでスレッドのサイズを設定することができるようです。
use std::thread;
fn recursion(n: usize) {
println!("Depth: {}", n);
// 再帰呼び出し
recursion(n + 1);
}
fn main() {
let builder = thread::Builder::new().stack_size(64 * 1024); // 64KB
let handler = builder.spawn(|| {
recursion(1);
}).unwrap();
handler.join().unwrap()
}
というわけで、再帰関数を用意し、スタックサイズを64KBにして実行してみます。
warning: function cannot return without recursing
--> src/main.rs:3:1
|
3 | fn recursion(n: usize) {
| ^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
...
6 | recursion(n + 1);
| ---------------- recursive call site
|
= help: a `loop` may express intention better if this is on purpose
= note: `#[warn(unconditional_recursion)]` on by default
warning: `rust-study` (bin "rust-study") generated 1 warning
Finished dev [unoptimized + debuginfo] target(s) in 0.40s
Running `target/debug/rust-study`
thread '' has overflowed its stack
fatal runtime error: stack overflow
Depth: 1
Depth: 2
Depth: 3
Depth: 4
Depth: 5
Depth: 6
~~省略~~
Depth: 468
Process finished with exit code 6
予想通りオーバーフローが発生しました。
スタックサイズを小さくしたら再帰の回数も減った。 しかし、極端に小さくした場合は、OSによってスタックの最小値が決まっているらしく、 それ以上小さくならないみたいです。
The actual stack size may be greater than this value if the platform specifies a minimal stack size.
ドキュメントにもそのように書かれています。
あと、再帰する怪しい関数に対してコンパイラが検出してWarningを出してくれてるのが便利だと思いました。
この記事を書いた人
-
2008年にアーティスへ入社。
システムエンジニアとして、SI案件のシステム開発に携わる。
その後、事業開発部の立ち上げから自社サービスの開発、保守をメインに従事。
ドメイン駆動設計(DDD)を中心にドメインを重視しながら、保守可能なソフトウェア開発を探求している。
この執筆者の最新記事
関連記事
最新記事
FOLLOW US
最新の情報をお届けします
- facebookでフォロー
- Twitterでフォロー
- Feedlyでフォロー