[Rust] tokio: Mutex
tokio๋ std::sync์ Mutex์ ๋ณ๊ฐ๋ก ์์ฒด์ ์ธ Mutex ๊ตฌํ์ฒด๋ฅผ ์ ๊ณตํ๋ค.
๋์ฒด๋ก๋ ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์์ง๋ง, ๋์ ๋ฐฉ์์ด ์กฐ๊ธ ๋ค๋ฆ์ ์ ์ํด์ผ ํ๋ค. ์ผ๋จ์, tokio ๋ฌธ์์์๋ ๊ฐ๊ธ์ std์ Mutex๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๊ถ์ฅํ๋ ํธ์ด๋ค.
๋๋ค ์์ด์ฐ๋๊ฑด ๋ฌธ์ ๊ฐ ์๋ค.
์ฌ์ฉ๋ฒ
์ผ๋จ ์ฌ์ฉ๋ฒ์ ํ์ค ๋ฎคํ ์ค์ ํฌ๊ฒ ๋ค๋ฅด์ง๋ ์๋ค.
์์ฑ๋ฐฉ์์ ๋์ผํ๋ฐ
๋ฎคํ
์ค ๊ฐ๋ ํ๋์ Result ๋ ์ด์ด๊ฐ ์๊ณ await์ ํตํด ๋๊ธฐํ๋ค๋ ๊ฒ์ด ์ข ๋ค๋ฅด๋ค.
์๋๋ ๊ฐ๋จํ ์์ ์ฝ๋ ์ ์ฒด๋ค.
use std::sync::Arc;
use tokio::sync::Mutex;
#[tokio::main]
async fn main() {
let _counter = Arc::new(Mutex::new(0));
let counter = _counter.clone();
let task1 = tokio::spawn(async move {
for _ in 0..1000 {
let mut counter = counter.lock().await;
*counter += 1;
}
});
let counter = _counter.clone();
let task2 = tokio::spawn(async move {
for _ in 0..1000 {
let mut counter = counter.lock().await;
*counter += 1;
}
});
let (_1, _2) = tokio::join!(task1, task2);
let counter = _counter.lock().await;
println!("Final counter value: {}", *counter);
}

๋ญ๊ฐ ๋ค๋ฅธ๊ฐ?
ํ์ค Mutex๋ lock์ ์ป์ ์ ์๋ ์ํ๋ฉด ์ผ๋จ ํ์ฌ ์ปจํ
์คํธ๋ฅผ ์ฐจ๋จํ๋ค. ๋ฌผ๋ก OS ๊ธฐ๋ฅ๋ค์ ํ์ฉํ๊ธฐ ๋๋ฌธ์ ๋นํจ์จ์ ์ธ ์ฐจ๋จ์ ํ์ง๋ ์๋๋ค.
tokio Mutex๋ lock์ ์ป์ ์ ์๋ ์ํ๋ฉด tokio executor์๊ฒ ์คํ์ ์๋ณดํ๋ค. FIFO ๊ธฐ๋ฐ์ผ๋ก ์ฐ์ ์์๊ฐ ์ง์ ๋๋ค.
os ์์ค์์ block ๋ฆฌ์์ค๋ฅผ ์๋ผ๋์ง, tokio ์์ค์์ ์๋ผ๋์ง์ ์ฐจ์ด์ผ ๋ฟ์ด๋ค.
๊ทผ๋ฐ ๋น๋๊ธฐ ์ปจํ
์คํธ์์๋ผ๋ ํ์ค Mutex๊ฐ ๋น์ฉ์ด ๋ ์ ๊ณ ํจ์จ์ ์ธ ๊ฒฝ์ฐ๊ฐ ๋ง๋ค.
ํนํ Mutex ๋ด๋ถ ๊ฐ์ด ๋จ์ํ ๋ฐ์ดํฐ์ฑ ๊ฐ์ด๋ผ๋ฉด ๊ทธ๋ฅ ํ์ค Mutex๊ฐ ํจ์ฌ ์ ํฉํ๋ค.
tokio Mutex๊ฐ ์ ํฉํ ๊ฒฝ์ฐ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ๊ณผ ๊ฐ์ I/O ๋ฆฌ์์ค๋ฅผ ๋ค๋ฃฐ ๋๋ค. ๊ทธ๋ฐ ํน๋ณํ ์ผ์ด์ค๊ฐ ์๋๋ผ๋ฉด ํ์ค Mutex๋ฅผ ์ฐ๋ ๊ฒ์ tokio์์๋ ๊ถํ๋ค.
์ฐธ์กฐ
https://stackoverflow.com/questions/73840520/what-is-the-difference-between-stdsyncmutex-vs-tokiosyncmutex
https://docs.rs/tokio/latest/tokio/sync/struct.Mutex.html#which-kind-of-mutex-should-you-use