함수명 f를 spawn 함수에 전달하여 새로운 쓰레드를 실행한다.
fn main() {
thread::spawn(f);
thread::spawn(f);
println!("Hello main");
}
fn f() {
println!(" Hello function");
let id = thread::current().id();
println!(" Hello thread: {id:?}");
}
Main 쓰레드가 자식 쓰레드 보다 먼저 종료되어 자식쓰레드의 출력 작업이 끝까지 수행되지 못한다.
root@DESKTOP-SCOK45O:~/mythread# cargo run
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s
Running `target/debug/mythread`
Hello main
Hello function
Hello thread: ThreadId(2)
Hello function
Hello thread: ThreadId(3)
root@DESKTOP-SCOK45O:~/mythread# cargo run
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
Running `target/debug/mythread`
Hello main
Hello function
Hello thread: ThreadId
root@DESKTOP-SCOK45O:~/mythread# cargo run
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
Running `target/debug/mythread`
Hello main
Hello function
Hello thread: ThreadId(
root@DESKTOP-SCOK45O:~/mythread# cargo run
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
Running `target/debug/mythread`
Hello main
Hello function
Hello thread:
Main 쓰레드가 먼저 종료되지 못하도록
fn main() {
let t1 = thread::spawn(f);
let t2 = thread::spawn(f);
println!("Hello main");
t1.join().unwrap();
t2.join().unwrap();
}
fn f() {
println!(" Hello function");
let id = thread::current().id();
println!(" Hello thread: {id:?}");
}
ThreadId(2), ThreadId(3) 이 반드시 실행되도록 보장되었다. 하지만 쓰레드의 잠금 단위가 함수 단위가 아니고 println! 단위이므로 각 함수의 출력 결과는 섞일 수 있다.
root@DESKTOP-SCOK45O:~/mythread# cargo run
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s
Running `target/debug/mythread`
Hello main
Hello function
Hello thread: ThreadId(3)
Hello function
Hello thread: ThreadId(2)
root@DESKTOP-SCOK45O:~/mythread# cargo run
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s
Running `target/debug/mythread`
Hello main
Hello function
Hello function
Hello thread: ThreadId(3)
Hello thread: ThreadId(2)
스태틱 변수에 대해 여러 쓰레드가 접근하는 방식은 컴파일 시점에 오류를 발생시킨다.
use std::thread;
fn main() {
static mut n : u32 = 0;
thread::scope(|s| {
for _ in 0..10 {
s.spawn(move || {
let id = thread::current().id();
for _ in 0..100 {
n += 1;
}
println!("Thread - {id:?} n - {n:}");
});
}
});
assert_eq!(n, 1000);
}
오류 내용
root@DESKTOP-SCOK45O:~/mythread# cargo run
Compiling mythread v0.1.0 (/root/mythread)
error[E0133]: use of mutable static is unsafe and requires unsafe function or block
--> src/main.rs:10:21
|
10 | n += 1;
| ^ use of mutable static
|
= note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
error[E0133]: use of mutable static is unsafe and requires unsafe function or block
--> src/main.rs:12:48
|
12 | println!("Thread - {id:?} n - {n:}");
| ^ use of mutable static
|
= note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
error[E0133]: use of mutable static is unsafe and requires unsafe function or block
--> src/main.rs:16:16
|
16 | assert_eq!(n, 1000);
| ^ use of mutable static
|
= note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
For more information about this error, try `rustc --explain E0133`.
error: could not compile `mythread` (bin "mythread") due to 3 previous errors
여러 쓰레드가 접근하는 공유 변수를 Mutax로 보호한다.
use std::sync::Mutex;
use std::thread;
fn main() {
let n = Mutex::new(0);
thread::scope(|s| {
for _ in 0..10 {
s.spawn(|| {
let id = thread::current().id();
let mut guard = n.lock().unwrap();
for _ in 0..100 {
*guard += 1;
}
println!("Thread - {id:?}, guard - {guard:?}");
});
}
});
assert_eq!(n.into_inner().unwrap(), 1000);
}
정상 수행 결과는 assert 에서 기대하는 값과 일치한다. guard 변수는 범위 내에서 유효하며 범위를 벗어나면 자연스럽게 사라진다. 모든 쓰레드 작업 후 into_inner() 를 사용해서 뮤텍스의 소유권을 가져온다. 이를 통해 뮤텍스의 잠금은 자연스럽게 해제된다.
root@DESKTOP-SCOK45O:~/mythread# cargo run
Compiling mythread v0.1.0 (/root/mythread)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.44s
Running `target/debug/mythread`
Thread - ThreadId(2), guard - 100
Thread - ThreadId(3), guard - 200
Thread - ThreadId(4), guard - 300
Thread - ThreadId(5), guard - 400
Thread - ThreadId(6), guard - 500
Thread - ThreadId(7), guard - 600
Thread - ThreadId(8), guard - 700
Thread - ThreadId(10), guard - 800
Thread - ThreadId(9), guard - 900
Thread - ThreadId(11), guard - 1000