【Rust】スレッド操作に慣れる
#rust #tips
Rustのスレッド操作の基本
hr.icon
基本
code: rust
use std::thread;
use std::time::Duration;
fn main() {
thread::spawn(|| {
for i in 1..10 {
// やあ!立ち上げたスレッドから数字{}だよ!
println!("hi number {} from the spawned thread!", i);
thread::sleep(Duration::from_millis(1));
}
});
for i in 1..5 {
// メインスレッドから数字{}だよ!
println!("hi number {} from the main thread!", i);
thread::sleep(Duration::from_millis(1));
}
}
スレッドの実行は、プロセスが終了したら中断される。
メインスレッドが立ち上げたスレッドの完了を待つ
code: rust
use std::thread;
use std::time::Duration;
fn main() {
let handle = thread::spawn(|| {
for i in 1..10 {
println!("hi number {} from the spawned thread!", i);
thread::sleep(Duration::from_millis(1));
}
});
for i in 1..5 {
println!("hi number {} from the main thread!", i);
thread::sleep(Duration::from_millis(1));
}
handle.join().unwrap();
}
handleを使う
ハンドルに対してjoinを呼び出すと、ハンドルが表すスレッドが終了するまで現在実行中のスレッドをブロックします。
スレッドに値を渡したい時は、moveを使って所有権を渡してあげる。
code: rust
use std::thread;
fn main() {
let v = vec!1, 2, 3;
let handle = thread::spawn(move || {
println!("Here's a vector: {:?}", v);
});
handle.join().unwrap();
}
https://doc.rust-jp.rs/book-ja/ch16-02-message-passing.html
チャンネルを使って、スレッド安全なデータのやり取りを行う。
スレッド間のデータやりとりの方法の1つonigiri.w2.icon
https://doc.rust-jp.rs/book-ja/ch16-03-shared-state.html
メッセージ受け渡しは、並行性を扱う素晴らしい方法ですが、唯一の方法ではありません。
「メモリを共有することでやり取りする。」
2つ目のデータの受け渡し方法だonigiri.w2.icon
共有メモリを使う。でもなぜ?
なぜチャンネルを使わないのか。一旦チャンネルに値を転送したら、その値は最早使用することがないから。
なるほど。所有権を渡すもんな。操作できない。
メモリ共有並行性は、複数の所有権に似ています: 複数のスレッドが同時に同じメモリ位置にアクセスできるのです。
なるほどonigiri.w2.icon
ミューテックス(Mutex)
mutual exclusion
どんな時も1つのスレッドにしかデータへのアクセスを許可しない。
スレッドはミューテックスにロックを要求し、ミューテックスは誰にもロックを渡してない場合はそれを渡す。
原則
1. データを使用する前にロックの獲得を試みなければならない。
2. ミューテックスが死守しているデータの使用が終わったら、他のスレッドがロックを獲得できるように、 データをアンロックしなければならない。
ミューテックスの管理は、正しく行うのに著しく技巧を要することがあるので、多くの人がチャンネルに熱狂的になる。 しかしながら、Rustの型システムと所有権規則のおかげで、ロックとアンロックをおかしくすることはありません。
へぇonigiri.w2.icon
へぇへぇへぇ
code: rust
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Result: {}", *counter.lock().unwrap());
}
これがthreadを使う時の基本形だろうなonigiri.w2.icon
Arc::new(Mutex::new(0));とか。
handle.join().unwrap();とか。