Rust: thread park unpark - grizlupo/_ GitHub Wiki

์ด๋ฆ„์œผ๋กœ๋„ ์ง์ž‘ ๋Œ€๋Š” ๊ฒƒ์ฒ˜๋Ÿผ park๋ฅผ ํ•˜๋ฉด ์Šค๋ ˆ๋“œ๋Š” ๋ฉˆ์ถ˜๋‹ค. park๋Š” ํ•จ์ˆ˜๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ธ์ˆ˜๊ฐ€ ์—†๋‹ค. ๋”ฐ๋ผ์„œ ๋Œ€์ƒ์ด ๋  ์Šค๋ ˆ๋“œ๋ฅผ ์ง€์ •ํ•  ์ˆ˜๊ฐ€ ์—†๋‹ค. ์ด ๋ง์€ ํ˜„์žฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๋ฉˆ์ถ˜๋‹ค๋Š” ๊ฒƒ์ผ ํ…Œ๊ณ , ์ด๊ฑด ๋‹ค์‹œ ์Šค์Šค๋กœ๋งŒ ๋ฉˆ์ถœ ์ˆ˜ ์žˆ๋‹ค๋Š” ๋ง์ด ๋œ๋‹ค.

๋ฐ˜๋ฉด์— unpark๋Š” ์Šค๋ ˆ๋“œ์˜ ๋ฉ”์†Œ๋“œ๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ ์Šค๋ ˆ๋“œ๋ฅผ ํŠน์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ฉˆ์ถฐ ์žˆ๋Š” ์Šค๋ ˆ๋“œ ์Šค์Šค๋กœ๋Š” ์•„๋ฌด๊ฒƒ๋„ ํ•  ์ˆ˜ ์—†์„ ํ…Œ๋‹ˆ๊นŒ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ unpark์„ ํ•ด์ค˜์•ผ ํ’€๋ฆฐ๋‹ค.

park ํ•จ์ˆ˜ ์„ค๋ช…์„œ์— ์‹ค๋ฆฐ ์˜ˆ์ œ๋ฅผ ๋ณด๋ฉด

use std::thread;
use std::sync::{Arc, atomic::{Ordering, AtomicBool}};
use std::time::Duration;

let flag = Arc::new(AtomicBool::new(false));
let flag2 = Arc::clone(&flag);

let parked_thread = thread::spawn(move || {
    // We want to wait until the flag is set. We *could* just spin, but using
    // park/unpark is more efficient.
    while !flag2.load(Ordering::Acquire) {
        println!("Parking thread");
        thread::park();
        // We *could* get here spuriously, i.e., way before the 10ms below are over!
        // But that is no problem, we are in a loop until the flag is set anyway.
        println!("Thread unparked");
    }
    println!("Flag received");
});

// Let some time pass for the thread to be spawned.
thread::sleep(Duration::from_millis(10));

// Set the flag, and let the thread wake up.
// There is no race condition here, if `unpark`
// happens first, `park` will return immediately.
// Hence there is no risk of a deadlock.
flag.store(true, Ordering::Release);
println!("Unpark the thread");
parked_thread.thread().unpark();

parked_thread.join().unwrap();

๋‚ด์šฉ์€ parked_thread๋ผ๋Š” ์Šค๋ ˆ๋“œ๋ฅผ ๋งŒ๋“ค๊ณ , ์Šค์Šค๋กœ ๋ฉˆ์ถ”๋ฉด ๋ฉ”์ธ ์Šค๋ ˆ๋“œ๊ฐ€ ์ด๋ฅผ ํ’€์–ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

์ข€ ๋” ๋œฏ์–ด ๋ณด๋ฉด

    while !flag2.load(Ordering::Acquire) {
        println!("Parking thread");
        thread::park();
        // We *could* get here spuriously, i.e., way before the 10ms below are over!
        // But that is no problem, we are in a loop until the flag is set anyway.
        println!("Thread unparked");
    }

parked_thread๋Š” flag2๊ฐ€ ์ฐธ์ผ ๋•Œ๊นŒ์ง€ thread::park();๋ฅผ ๋ฐ˜๋ณตํ•˜๋„๋ก ๋˜์–ด ์žˆ๋‹ค. flag2๋Š” ๊ผด๋ž‘ ์ฐธ/๊ฑฐ์ง“ ํ™•์ธ์ด ๋ชฉ์ ์ด์ง€๋งŒ, ๋‘ ์Šค๋ ˆ๋“œ์—์„œ ๊ณต์œ ํ•˜๋Š” ๊ฐ’์ด๋‹ค ๋ณด๋‹ˆ AtomicBool ํ˜•์ด๋ผ ๊ฑฐ์ฐฝํ•˜๋‹ค. atomic ์—ฐ์‚ฐ์— ์ฃผ์–ด์ง„ Ordering์— ๋Œ€ํ•ด์„œ๋Š” ์”น์–ด๋จน๋Š” C++ - <15 - 3. C++ memory order ์™€ atomic ๊ฐ์ฒด> ์ด ์„ค๋ช…์ด C++์„ ๊ธฐ์ค€์œผ๋กœ ํ•˜์ง€๋งŒ ์ž˜ ๋˜์–ด ์žˆ๋‹ค.

๋ฉ”์ธ ์Šค๋ ˆ๋“œ๋Š”

flag.store(true, Ordering::Release);
println!("Unpark the thread");
parked_thread.thread().unpark();

flag๋ฅผ ์ฐธ์œผ๋กœ ์ค€๋‹ค. flag๊ณผ flag2๋Š” Arc๋กœ clone๋œ ๊ฐ’์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ฐ™์€ ๊ฒƒ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  parked_thread.thread().unpark(); ํ•œ๋‹ค. parked_thread๋Š” ํ’€๋ฆด ๊ฒƒ์ด๊ณ , flag๋ฅผ ์ด๋ฏธ ์ฐธ์œผ๋กœ ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— while ๋ฌธ์ด ๋๋‚˜๋ฉด์„œ ์Šค๋ ˆ๋“œ๋„ ๋๋‚  ๊ฒƒ์ด๋‹ค.

์‹คํ–‰์‹œํ‚ค๋ฉด

Parking thread
Unpark the thread
Thread unparked
Flag received

์ด๋ ‡๊ฒŒ ๋œ๋‹ค.

์˜ˆ์ œ๋Š” flag๋ฅผ ์ฐธ์œผ๋กœ ์ฃผ๊ณ , unpark๋ฅผ ํ•˜์ง€๋งŒ ๋งŒ์•ฝ ๊ทธ๋ƒฅ unpack๋งŒ ํ•œ๋‹ค๋ฉด parked_thread๋Š” ๋‹ค์‹œ park๋˜๋ฉด์„œ ๋ฉˆ์ถœ ๊ฒƒ์ด๋‹ค. flag๋ฅผ ์ฐธ์œผ๋กœ ์ฃผ๊ธฐ ์ „๊นŒ์ง€๋Š” unpack๋ฅผ ํ•ด๋„ ๊ณ„์† ๋‹ค์‹œ park ๋  ๊ฒƒ์ด๋‹ค.