TL;DR
Arc์ atomic ์ฐธ์กฐ ์๋ฅผ ์ด์ฉํ thread ๊ฐ ๊ณต์ ์์ ๊ถMutexGuard์ ์๋ช ์ผ๋ก ์ ํํ๋ ๋ด๋ถ ๊ฐ์ ๋ฐฐํ์ ์ ๊ทผArc<Mutex<T>>์ thread๋ณ stack๊ณผ ๊ณต์ heap ํ ๋น
AI-assisted
1. Thread๋ณ stack๊ณผ ๊ณต์ heap
Rc์ RefCell์ ์กฐํฉํ๋ฉด ๊ฐ์ thread์ ์ฌ๋ฌ ์์ ์๊ฐ ๊ฐ์ ๊ฐ์ ์์ ํ ์ ์๋ค. ์ฌ๋ฌ thread์์๋ ์ด ๊ด๊ณ๋ฅผ ๋ง๋ค๋ ค๋ฉด ๊ณต์ ์์ ๊ถ๊ณผ ๊ฐ์ ๋ณ๊ฒฝ์ ๊ฐ๊ฐ ๋๊ธฐํํด์ผ ํ๋ค.
๊ฐ OS thread๋ ์์ ์ stack๊ณผ ์ง์ญ ์ํ๋ฅผ ์ฌ์ฉํ๋ค. ๊ฐ์ ํ๋ก์ธ์ค์ heap ํ ๋น์ thread ์ฌ์ด์์ ๊ณต์ ํ ์ ์์ผ๋ฏ๋ก ์๋ก ๋ค๋ฅธ stack์ ํฌ์ธํฐ๊ฐ ๊ฐ์ ๊ฐ์ ๊ฐ๋ฆฌํฌ ์ ์๋ค.
- ๊ณต์ ์์ ๊ถ: ๊ฐ thread๊ฐ ํ์๋ก ํ๋ ๋์ ๊ฐ์ ๊ฐ์ ์๋ช
์ ์ ์งํ๋ค.
Rc๋ cloneยทdrop ๋ ์ฐธ์กฐ ์๋ฅผ non-atomic ์ฐ์ฐ์ผ๋ก ๋ฐ๊พธ๋ฏ๋ก thread ์ฌ์ด์ ๊ณต์ ํ ์ ์๋ค. - ๊ณต์ ๊ฐ์ ๋ณ๊ฒฝ: ์ฌ๋ฌ thread๊ฐ ๊ฐ์ ๊ฐ์ ์์ ํ ๋ ์ ๊ทผ์ ๋๊ธฐํํ๋ค.
RefCell์ borrow ๊ฒ์ฌ๋ thread ๊ฐ ๋๊ธฐํ๋ฅผ ์ ๊ณตํ์ง ์๋๋ค.
Arc๋ ์ฒซ ์๊ตฌ๋ฅผ, Mutex๋ ๋ ๋ฒ์งธ ์๊ตฌ๋ฅผ ๋งก๋๋ค. ๋ ์๊ตฌ๊ฐ ํจ๊ป ์์ผ๋ฉด Arc<Mutex<T>>๋ฅผ ์ด๋ค.
๋์: ๋ฉ๋ชจ๋ฆฌ ๊ด๊ณ์ ๊ฐ๋ ๋ชจํ
thread์ ์ง์ญ ๊ฐ์ stack์ ํ์ํ๋ค. ์ค์ ABIยท์ต์ ํยทOS๋ณ lock ๋ถ๊ฐ ์์์ ์๋ตํ๋ฉฐ ์์ ยท๋น๋ฆผยท๊ฐ์ ํฌํจ ๊ด๊ณ๋ฅผ ๋ํ๋ธ๋ค.
2. Arc: A thread-safe reference-counting pointer
A thread-safe reference-counting pointer. (Arc)
Arc<T>๋ heap์ ๊ฐ์ T๋ฅผ ์ฌ๋ฌ ์์ ์๊ฐ ํจ๊ป ์์ ํ๋ ํฌ์ธํฐ๋ค. Arc::clone์ T๋ฅผ ๋ณต์ ํ์ง ์๊ณ ๊ฐ์ ํ ๋น์ ๊ฐ๋ฆฌํค๋ Arc๋ฅผ ํ๋ ๋ ๋ง๋ ๋ค. ์ฐธ์กฐ ์์ ์ฆ๊ฐ์ atomic ์ฐ์ฐ์ผ๋ก ์ฒ๋ฆฌํ๋ฏ๋ก ์ฌ๋ฌ thread์ cloneยทdrop์ด ๊ฒน์ณ๋ ์ฐธ์กฐ ์๋ฅผ ์์ ํ๊ฒ ๊ด๋ฆฌํ๋ค.
๋ค์ ์์ ์์๋ main๊ณผ worker๊ฐ ๊ฐ์ ์ซ์ 10์ ์ฝ๋๋ค.
use std::sync::Arc;
use std::thread;
fn main() {
let number = Arc::new(10);
let worker_number = Arc::clone(&number);
let worker = thread::spawn(move || {
assert_eq!(*worker_number, 10);
});
// ๋์ ์์ โ : spawn ๋ฐํ ๋ค worker_number๊ฐ ์์ง ์ด์ ์๋ ๊ฐ๋ฅํ ์์
assert_eq!(*number, 10);
worker.join().unwrap();
assert_eq!(Arc::strong_count(&number), 1);
}์์ โ ์ spawn์ด ๋ฐํ๋ ๋ค worker๊ฐ ์์ง Arc๋ฅผ ๋ณด์ ํ ๊ฐ๋ฅํ ์คํ ์ํ๋ค. worker๊ฐ ๋จผ์ ๋๋ ์๋ ์์ผ๋ฏ๋ก ์ฐธ์กฐ ์๊ฐ 1์ด๋ผ๋ ๊ฒ์ฌ๋ join() ๋ค์ ๋๋ค.
flowchart TB subgraph A_MAIN["Main thread์ Stack"] A_NUMBER["number: Arc<i32>"] A_JOIN["worker: JoinHandle / ์ข ๋ฃ ๋๊ธฐ์ฉ"] end subgraph A_WORKER["Worker thread์ Stack"] A_WORKER_NUMBER["worker_number: Arc<i32>"] end subgraph A_HEAP["๊ณต์ Heap"] subgraph A_ALLOCATION["Arc ํ ๋น ํ๋"] A_COUNT["atomic strong count: 2"] A_VALUE["๋ด๋ถ i32 ๊ฐ: 10"] end end A_NUMBER -->|๊ณต์ ์์ | A_ALLOCATION A_WORKER_NUMBER -->|๊ณต์ ์์ | A_ALLOCATION
move:worker_number์ ์์ ๊ถ์ worker์ closure๋ก ๋๊ธด๋ค. main์๋number์ ์ข ๋ฃ ๋๊ธฐ์ฉworker๊ฐ ๋จ๋๋ค.- ๊ฐ์ ์ซ์: ๋ Arc๊ฐ ๊ฐ์ ํ ๋น์
10์ ์ฝ๋๋ค.Arc::clone์ ๋ณ๋ ์ซ์๋ฅผ ๋ง๋ค์ง ์๋๋ค. - ์ข
๋ฃ ๋ค: worker์ Arc๊ฐ drop๋๋ฉด
number๋ง ๋จ์ strong count๋1์ด๋ค. ๋ง์ง๋ง Arc๋ drop๋๋ฉด ๋ด๋ถ T๊ฐ drop๋๋ค.
์ฃผ์ API๋ Rc์ ์ฃผ์ method์ ๋น์ทํ๋ค. get_mut๊ณผ make_mut๋ ๊ฐ์ ์์ ๊ถ ์๋ฆฌ๋ก ๋์ํ๋ค. ์ฌ๋ฌ ์์ ์๊ฐ ์์ ๋ make_mut์ผ๋ก ๊ฐ์ ๋ถ๋ฆฌํ๋ฉด ๋ค๋ฅธ Arc๋ ๊ธฐ์กด ๊ฐ์ ๊ณ์ ์์ ํ๋ค.
Arc๊ฐ ๋๊ธฐํํ๋ ๋์์ ์์ ์ ์ฐธ์กฐ ์๋ค. ๋ด๋ถ T์ ๋ณ๊ฒฝ์๋ T๊ฐ ์ ๊ณตํ๋ ๋๊ธฐํ API๊ฐ ํ์ํ๋ฉฐ ์ผ๋ฐ์ ์ธ thread ๊ฐ Arc ๊ณต์ ์กฐ๊ฑด์ T: Send + Sync๋ค.
3. Mutex: A mutual exclusion primitive
main๊ณผ worker๊ฐ ๊ฐ์ ์ซ์๋ฅผ ๊ฐ๊ฐ 1์ฉ ๋๋ฆฌ๋ ค๋ฉด ๊ฐ์ ์ฝ๊ณ ๋ํ๊ณ ์ฐ๋ ๋์ ๋ค๋ฅธ thread์ ์์ ์ ๋ง์์ผ ํ๋ค. ๋ thread๊ฐ ๋ชจ๋ 0์ ์ฝ๊ณ 1์ ์ฐ๋ฉด ์ฆ๊ฐ ํ๋๊ฐ ๋๋ฝ๋๋ค. Mutex<T>๋ lock์ ์ป์ thread ํ๋๊ฐ ๋ด๋ถ T์ ์ ๊ทผํ๋๋ก ์ ํํ๋ค.
A mutual exclusion primitive useful for protecting shared data (Mutex)
3.1 lock๊ณผ guard์ ๊ธฐ๋ณธ ๋์
lock()์ด ์ฑ๊ณตํ๋ฉด Mutex๋ฅผ ๋น๋ฆฌ๋ MutexGuard<T>๋ฅผ ์ป๋๋ค. guard๋ก ๋ด๋ถ ๊ฐ์ ์ฝ๊ฑฐ๋ ์์ ํ๊ณ guard๊ฐ drop๋ ๋ unlockํ๋ค.
When this structure is dropped (falls out of scope), the lock will be unlocked.
| ์ ๊ทผ | ๋ค๋ฅธ thread๊ฐ lock์ ๋ณด์ ํ ๊ฒฝ์ฐ | ๋ฐํ๊ณผ ํด์ |
|---|---|---|
lock() | ํ๋ํ ๋๊น์ง ๋๊ธฐ | ์ฑ๊ณตํ๋ฉด guard, guard์ drop์ผ๋ก unlock |
try_lock() | ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ WouldBlock ์ค๋ฅ ๋ฐํ | ํ๋์ ์ฑ๊ณตํ๋ฉด ๊ฐ์ guard |
ํ์ค MutexGuard๋ Send๊ฐ ์๋๋ฏ๋ก lock์ ์ป์ thread์์ ํด์ ํ๋ค. guard์ ๋ง์ง๋ง ์ฌ์ฉ์ด ๊ณง drop์ ์๋์ด์ ๋ธ๋ก์ด๋ drop(guard)๋ก lock ์ ์ง ๋ฒ์๋ฅผ ์ ํ๋ค.
Mutex๋ ๊ณต์ ์์ ๊ถ์ ์ ๊ณตํ์ง ์์ผ๋ฉฐ T๋ฅผ ์์ ์ ํ๋์ ๋ด๋๋ค. Mutex<i32>์ ์ซ์๋ Mutex ์์ ๋ค์ด๊ฐ๊ณ Mutex๋ฅผ ์ง์ญ ๊ฐ์ผ๋ก ๋๋ฉด ๊ทธ ์ซ์๋ฅผ ์ํ ๋ณ๋ heap ํ ๋น์ ํ์ํ์ง ์๋ค. Arc ์์ ๋ด์ผ๋ฉด Mutex์ ์ซ์๊ฐ ํจ๊ป Arc์ heap ํ ๋น ์์ ๋์ธ๋ค.
3.2 ๋ thread์ ๊ณต์ ๊ฐ ์์
main๊ณผ worker๊ฐ ๊ฐ์ counter๋ฅผ ๊ณต์ ํ๋ฉฐ ๊ฐ๊ฐ 1์ ๋ํ๋ ์์ ๋ค.
use std::sync::Mutex;
use std::thread;
fn main() {
let counter = Mutex::new(0);
thread::scope(|scope| {
// main thread
scope.spawn(|| {
// ์ด ๋ณธ๋ฌธ๋ง ์ worker thread์์ ์คํ
let mut worker_guard = counter.lock().unwrap();
*worker_guard += 1;
}); // worker ์์์ guard๊ฐ drop๋๋ฉฐ unlock
{
// main thread
let mut main_guard = counter.lock().unwrap();
*main_guard += 1;
} // main ์์์ guard๊ฐ drop๋๋ฉฐ unlock
}); // worker๊ฐ ๋๋ ๋๊น์ง ๊ธฐ๋ค๋ฆผ
assert_eq!(*counter.lock().unwrap(), 2);
}counter ์์ฒด๋ฅผ move๋ก worker์ ๋๊ธฐ๋ฉด Mutex์ ์์ ๊ถ๋ worker๋ก ์ด๋ํ๋ฏ๋ก main์ ๊ฐ์ Mutex์ ์ ๊ทผํ ์ ์๋ค. worker๊ฐ Mutex๋ฅผ ๋ฐํํ๋๋ก ์์ฑํ๋ฉด main์ด join()์ผ๋ก ์์ ๊ถ์ ๋๋ ค๋ฐ์ ๋ค์ ์ฌ์ฉํ ์ ์๋ค. ์ด ๊ฒฝ์ฐ์๋ worker์ ์์
์ด ๋๋ ๋ค main์ด ๊ฐ์ Mutex๋ฅผ ์ด์ด์ ์ฌ์ฉํ๋ ์์ฐจ์ ์ธ ๊ตฌ์กฐ๊ฐ ๋๋ค.
๋ thread๊ฐ ๊ฐ์ Mutex๋ฅผ ํจ๊ป ์ฌ์ฉํ ์ ์๋๋ก ์ด ์์ ์์๋ thread::scope๋ฅผ ์ฌ์ฉํ๋ค.
- main์
counter์ ์์ ๊ถ์ ์ ์งํ ์ฑ worker์&Mutex<i32>๋ฅผ ๋น๋ ค์ค๋ค. thread::scope๋ ๋ฐํ๋๊ธฐ ์ ์ worker๋ฅผ ์๋์ผ๋ก joinํ๋ค. worker๋counter๊ฐ drop๋๊ธฐ ์ ์ ์์ ์ ๋ง์น๋ค.- ๊ฐ thread๋ ์๊ธฐ ์์์
lock()์ผ๋ก guard๋ฅผ ์ป์ด ๊ฐ์ ์์ ํ๋ค. guard๊ฐ drop๋ ๋ ์ ๊ธ์ด ํ๋ฆฐ๋ค.
3.3 lock์ ๋ฐํ๊ฐ๊ณผ poisoning
์์ ์ counter.lock().unwrap()์์ lock()์ Result๋ฅผ ๋ฐํํ๋ค. ์ด์ ์ฌ์ฉ ์ค ๋ฐ์ํ panic ๋๋ฌธ์ ๋ด๋ถ ๊ฐ์ ์ผ๊ด์ฑ์ ํ์ธํด์ผ ํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
- ์ ์ ์ฌ์ฉ:
Ok(guard)๋ก ๊ฐ์ ์ฌ์ฉํ๊ณ guard๊ฐ drop๋๋ฉด ์ ๊ธ์ด ํ๋ฆฐ๋ค. - panic์ผ๋ก ์ค๋จ: guard๋ฅผ ๋ณด์ ํ ์ฑ panic์ผ๋ก scope๋ฅผ ๋น ์ ธ๋๊ฐ๋ฉด guard๋ฅผ ์ ๋ฆฌํ๋ฉด์ ์ ๊ธ์ ํ๊ณ poisoned ์ํ๋ฅผ ๊ธฐ๋กํ๋ค. ๋ฐ์ดํฐ ์์ ์ด ์ค๊ฐ์ ๋๊ฒผ์ ์ ์๋ค๋ ํ์๋ค.
- ์ดํ ์ ๊ทผ: poisoned ์ํ์์๋ ๋ค์
lock()์ด ์ ๊ธ์ ์ป๋๋ผ๋Err(PoisonError)๋ฅผ ๋ฐํํด ๋ฐ์ดํฐ ํ์ธ์ด ํ์ํจ์ ์๋ฆฐ๋ค.
์์ ์ .unwrap()์ ์ด ์ค๋ฅ๋ฅผ ๋ค์ panic์ผ๋ก ์ฒ๋ฆฌํ๋ค. ๋ณต๊ตฌ๊ฐ ํ์ํ๋ฉด ์ค๋ฅ์ into_inner()๋ก guard๋ฅผ ๊บผ๋ด ๋ฐ์ดํฐ๋ฅผ ํ์ธยท์์ ํ๊ณ clear_poison()์ผ๋ก ํ์๋ฅผ ์ง์ธ ์ ์๋ค.
4. Arc<Mutex<T>>: Thread-safe shared mutable state
๋ฐฑ๊ทธ๋ผ์ด๋ ํ์ผ ์ฒ๋ฆฌ์์๋ worker๊ฐ ํ์ผ์ ์ฒ๋ฆฌํ๋ ๋์ main์ด ์งํ ์ํ๋ฅผ ํ์ํ๊ณ ์ทจ์ ์์ฒญ์ ๋ฐ๋๋ค. ์์
์ ์์ํ๋ start_job()์ worker์ ์๋ฃ๋ฅผ ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ ๋ฐํํด์ผ ํ๋ค. main์ ๊ทธ ๋ค์๋ ๋ค๋ฅธ ์์
์ ํ๋ฉด์ ์ฒ๋ฆฌ ๊ฐ์๋ฅผ ์ฝ๊ฑฐ๋ ์ทจ์๋ฅผ ์์ฒญํ ์ ์์ด์ผ ํ๋ค.
์์ thread::scope ์์ ๋ scope๋ฅผ ๋ฒ์ด๋๊ธฐ ์ ์ worker์ ์ข
๋ฃ๋ฅผ ๊ธฐ๋ค๋ ธ๋ค. ์ด ๋ฐฉ์์ start_job() ์์ ์ฐ๋ฉด main์ด ์ํ๋ฅผ ์ ๋ฌ๋ฐ์ ๋๋ ์์
์ด ์ด๋ฏธ ๋๋ ์๋ค. thread::spawn์ผ๋ก ๋ง๋ worker๋ ์์ ์ ์์ํ ํจ์๋ณด๋ค ์ค๋ ์คํ๋ ์ ์๋ค.
threads can outlive the lifetime they have been created in.
ํจ์ ๋ฐํ ๋ค์๋ worker๊ฐ ์ฌ์ฉํ ์ํ๋ฅผ ํจ์์ local variable์ ๋ํ ์ฐธ์กฐ๋ก ๋น๋ ค์ค ์๋ ์๋ค. ๋ค์ ์์ ์์๋ Arc<Mutex<JobState>>๋ฅผ ๋ง๋ค์ด main๊ณผ worker๊ฐ ๊ฐ์ ์ํ๋ฅผ ํจ๊ป ์์ ํ๋ค.
- Arc: ๊ฐ์ heap ํ ๋น์ ๊ฐ๋ฆฌํค๋ Arc๋ฅผ main๊ณผ worker์ ํ๋์ฉ ์ค๋ค.
start_job()์ด ๋ฐํ๋ ๋ค์๋ ๋ ์์ ์๊ฐ ๊ฐ์ ์ํ๋ฅผ ์ฌ์ฉํ ์ ์๋ค. - Mutex: worker์ ์ฒ๋ฆฌ ๊ฐ์ ๊ฐฑ์ ๊ณผ main์ ์งํ ์ํ ์กฐํยท์ทจ์ ์์ฒญ์ ๋๊ธฐํํ๋ค. ์ฌ๋ฌ Arc๊ฐ ๊ฐ์
JobState๋ฅผ ๊ณต์ ํ๋ ๋์์๋&mut JobState๋ฅผ ์ป์ ์ ์์ผ๋ฏ๋ก Mutex์ guard๋ก ์์ ํ๋ค.
์์ ๋ ์ค์ ํ์ผ I/O ๋์ sleep()์ผ๋ก ํ์ผ ํ๋์ ์ฒ๋ฆฌ ์๊ฐ์ ํ๋ด ๋ธ๋ค. ํ์ผ ์ฒ๋ฆฌ๋ lock์ ๋ณด์ ํ์ง ์์ ์ํ์์ ์ํํ๊ณ ์ํ๋ฅผ ํ์ธํ๊ฑฐ๋ ๋ฐ๊พธ๋ ๋์๋ง lock์ ์ป๋๋ค.
use std::sync::{Arc, Mutex};
use std::thread::{self, JoinHandle};
use std::time::Duration;
struct JobState {
completed: usize,
cancelled: bool,
}
fn start_job() -> (Arc<Mutex<JobState>>, JoinHandle<()>) {
let state = Arc::new(Mutex::new(JobState {
completed: 0,
cancelled: false,
}));
let worker_state = Arc::clone(&state);
let worker = thread::spawn(move || {
for _ in 0..100 {
if worker_state.lock().unwrap().cancelled {
break;
}
// ํ์ผ ํ๋๋ฅผ ์ฒ๋ฆฌํ๋ค๊ณ ๊ฐ์ . ์ด ๋์์๋ lock์ ๋ณด์ ํ์ง ์๋๋ค.
thread::sleep(Duration::from_millis(10));
worker_state.lock().unwrap().completed += 1;
}
});
(state, worker) // worker์ ์ข
๋ฃ๋ฅผ ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ ์์ ๊ถ์ ํธ์ถ์์๊ฒ ๋ฐํ
}
fn main() {
let (state, worker) = start_job();
{
let snapshot = state.lock().unwrap();
println!("์ฒ๋ฆฌํ ํ์ผ: {}", snapshot.completed);
// ๋์ ์์ โ : main์ด lock์ ๋ณด์ ํ๊ณ worker๊ฐ ๋ค์ lock์ ๊ธฐ๋ค๋ฆฌ๋ ๊ฐ๋ฅํ ์์
} // snapshot์ด drop๋๋ฉฐ unlock
state.lock().unwrap().cancelled = true;
worker.join().unwrap();
// ๋์ ์์ โก: worker ์ข
๋ฃ ๋ค, ์๋ ๊ฒ์ฌ์ฉ lock์ ์ป๊ธฐ ์
assert!(state.lock().unwrap().cancelled);
assert_eq!(Arc::strong_count(&state), 1);
}start_job()์ state์ worker๋ ๋ฐํ๊ฐ์ผ๋ก ์ด๋ํ๊ณ worker_state๋ worker์ closure๋ก ์ด๋ํ๋ค. worker๋ ํจ์ ์์ local variable์ ๋น๋ฆฌ์ง ์์ผ๋ฏ๋ก ํจ์๊ฐ ๋ฐํ๋ ๋ค์๋ ์คํํ ์ ์๋ค. ์ถ๋ ฅ๋๋ ์ฒ๋ฆฌ ๊ฐ์๋ ๋ thread์ ์คํ ์์์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋ค.
์์ โ ์ main์ด snapshot์ ๋ณด์ ํ๊ณ worker๊ฐ ์ํ ํ์ธ์ด๋ ๊ฐฑ์ ์ ์ํ lock์์ ๊ธฐ๋ค๋ฆฌ๋ ๊ฐ๋ฅํ ์ํ๋ค. n์ ์ด๋๊น์ง ์ฒ๋ฆฌํ ํ์ผ ๊ฐ์๋ค.
flowchart TB subgraph B_MAIN["Main thread์ Stack / start_job ๋ฐํ ๋ค"] B_STATE["state: Arc<Mutex<JobState>>"] B_SNAPSHOT["snapshot: MutexGuard<JobState>"] B_JOIN["worker: JoinHandle"] end subgraph B_WORKER["Worker thread์ Stack"] B_WORKER_STATE["worker_state: Arc<Mutex<JobState>>"] B_WAIT["lock์์ ๋๊ธฐ / guard ์์ฑ ์ "] end subgraph B_HEAP["๊ณต์ Heap"] subgraph B_ALLOCATION["Arc ํ ๋น ํ๋"] B_COUNT["atomic strong count: 2"] subgraph B_MUTEX["Mutex<JobState>"] B_LOCK["lock: ์ ๊น / main์ด ๋ณด์ "] B_DATA["JobState<br/>completed: n<br/>cancelled: false"] end end end B_STATE -->|๊ณต์ ์์ | B_ALLOCATION B_WORKER_STATE -->|๊ณต์ ์์ | B_ALLOCATION B_SNAPSHOT -->|Mutex ์ฐธ์กฐ| B_MUTEX B_SNAPSHOT -.->|drop ์ unlock| B_LOCK B_WAIT -.->|ํ๋ ๋๊ธฐ| B_LOCK
- ๊ณต์ ์์ ๊ถ
- main๊ณผ worker์ Arc๊ฐ ๊ฐ์ Mutex์
JobStateํ๋๋ฅผ ์์ snapshot์ ์ป๊ฑฐ๋ dropํด๋ strong count๋ ๋ฐ๋์ง ์์
- main๊ณผ worker์ Arc๊ฐ ๊ฐ์ Mutex์
- ์ ๊ธ ๋ฒ์
snapshot์ด ์๋ ๋์ worker๋ ๊ฐ์ Mutex์ lock์ ์ป์ ์ ์์- main์ ์ด guard๋ฅผ ๋จผ์ dropํ ๋ค ์ ์์ guard๋ก
cancelled๋ฅผ ๋ณ๊ฒฝ
- ์ทจ์ ํ์ธ
- worker๋ ๋ฐ๋ณต์ ์์ํ ๋
cancelled๋ฅผ ํ์ธ - ์ด๋ฏธ ์์ํ ํ์ผ ์ฒ๋ฆฌ๋ ๋๋ ์ ์์ผ๋ฉฐ ์ทจ์ ์์ฒญ์ ํ์ธํ๋ฉด ๋ค์ ํ์ผ์ ์ฒ๋ฆฌํ์ง ์๊ณ ์ข ๋ฃ
- worker๋ ๋ฐ๋ณต์ ์์ํ ๋
์์ โก์์๋ join()์ผ๋ก worker์ ์ข
๋ฃ๋ฅผ ํ์ธํ๋ค. worker์ Arc๊ฐ drop๋์ด main์ Arc๋ง ๋จ๊ณ m์ ์ต์ข
์ฒ๋ฆฌ ๊ฐ์๋ค.
flowchart TB subgraph C_MAIN["Main thread์ Stack"] C_STATE["state: Arc<Mutex<JobState>>"] end C_WORKER["Worker thread ์ข ๋ฃ<br/>worker_state drop ์๋ฃ"] subgraph C_HEAP["๊ณต์ Heap"] subgraph C_ALLOCATION["Arc ํ ๋น ํ๋"] C_COUNT["atomic strong count: 1"] subgraph C_MUTEX["Mutex<JobState>"] C_LOCK["lock: ํ๋ฆผ"] C_DATA["JobState<br/>completed: m<br/>cancelled: true"] end end end C_STATE -->|๊ณต์ ์์ | C_ALLOCATION
- ๋จ์ ์์ ์
join()์worker๋ฅผ ์๋นํ๋ฏ๋ก main์ Stack์๋ JoinHandle์ด ๋จ์ง ์๊ณ ์ํ๋ main์state๊ฐ ๊ณ์ ์์
- ๋ฐ๋ฉ ์์
- worker๊ฐ ๋๋๋ main์ ์ํ๋ฅผ ์ฝ์ ์ ์์
- ๋ง์ง๋ง Arc๊ฐ drop๋ ๋ Mutex์ ๋ด๋ถ
JobState๊ฐ drop
5. ํ์ ์ ํ๊ณผ thread ๊ณต์ ์กฐ๊ฑด
| ํ์ | ๊ณต์ ์์ ๊ถ | ๋ด๋ถ T์ ์์น | ์์ ๊ฒฝ๋ก | thread ๊ฐ ๊ณต์ ์กฐ๊ฑด |
|---|---|---|---|---|
Arc<T> | ์ ๊ณต | Arc์ heap ํ ๋น ์ | get_mutยทmake_mut ๋๋ T์ ๋๊ธฐํ API | T: Send + Sync |
Mutex<T> | ์ ๊ณต ์ ํจ | Mutex ์์ ์ ํ๋ | lockยทtry_lock์ guard | T: Send |
Arc<Mutex<T>> | ์ ๊ณต | Arc ํ ๋น ์์ Mutex ํ๋ | Mutex์ guard | T: Send |
Send๋ ๊ฐ์ ์์ ๊ถ์ ๋ค๋ฅธ thread๋ก ๋๊ฒจ๋ ์์ ํจ์ ๋ํ๋ธ๋ค.Sync๋ ๊ณต์ ์ฐธ์กฐ&T๋ฅผ thread ์ฌ์ด์ ๋๊ฒจ๋ ์์ ํจ์ ๋ํ๋ธ๋ค.T: Sync์ ์ ์๋&T: Send๋ค.
Mutex<T>๋ T: Send์ด๋ฉด Send์ Sync๋ฅผ ๊ตฌํํ๋ค. guard๋ก T๋ฅผ ๊ต์ฒดํด ๊บผ๋ด๋ thread๊ฐ ๋ฌ๋ผ์ง ์ ์์ผ๋ฏ๋ก T๋ thread ์ฌ์ด์์ ์ด๋ํ ์ ์์ด์ผ ํ๋ค. lock์ ์ป์ thread์ ์ฐจ๋ก๋ก ๋ฐฐํ์ ์ ๊ทผ์ ์ ๊ณตํ๋ฏ๋ก T ์์ฒด์ Sync๋ ์๊ตฌํ์ง ์๋๋ค.
Arc ์์ ํ์
์ด Mutex<T>์ผ ๋๋ T: Send๋ง์ผ๋ก Mutex๊ฐ Send + Sync๋ฅผ ๋ง์กฑํ๋ฏ๋ก Arc์ ๊ณต์ ์กฐ๊ฑด๋ ์ถฉ์กฑํ๋ค.
| ํ์ํ ๋์ | ์ ํํ ์ ์๋ ํ์ |
|---|---|
| ์ฌ๋ฌ thread๊ฐ ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์์ ํ๋ฉฐ ์ฝ๊ธฐ | Arc<T> |
| ์๋ช ์ ๋ค๋ฅธ ๋ฐฉ์์ผ๋ก ํ๋ณดํ ๊ฐ์ ์ฌ๋ฌ thread๊ฐ lock์ผ๋ก ์ ๊ทผ | Mutex<T>์ ๊ณต์ ์ฐธ์กฐ |
| ์ฌ๋ฌ thread๊ฐ ๊ฐ์ ๊ฐ์ ์์ ํ๋ฉฐ lock์ผ๋ก ์์ | Arc<Mutex<T>> |
Arc<RefCell<T>>๋ RefCell<T>๊ฐ Sync๊ฐ ์๋๋ฏ๋ก thread ๊ฐ ๊ณต์ ์ ์ธ ์ ์๋ค. Arc<Mutex<Rc<T>>>๋ ๋ด๋ถ Rc๊ฐ Send๊ฐ ์๋์ด์ ์กฐ๊ฑด์ ๋ง์กฑํ์ง ์๋๋ค. RefCell์ T๊ฐ Send์ด๋ฉด ์์ ๊ถ์ ๋ค๋ฅธ thread๋ก ์ฎ๊ธธ ์ ์์ง๋ง ๊ฐ์ RefCell์ ์ฌ๋ฌ thread๊ฐ ๊ณต์ ํ๋๋ก ๋๊ธฐํํ์ง๋ ์๋๋ค.
๊ฐ์ ์๋ช ์ ๋น๋ฆผ์ผ๋ก ํํํ ์ ์์ผ๋ฉด ๊ณต์ ์์ ๊ถ์ ์ถ๊ฐํ ํ์๊ฐ ์๋ค. ๊ฐ์ thread ์์์ ์์ ๊ถ๊ณผ ๊ฐ๋ณ ์ ๊ทผ์ ์กฐํฉํ ๋๋ Rc์ RefCell์ ์ฌ์ฉํ ์ ์๋ค.