C.W.K.
Stream
Lesson 03 of 06 · published

공유 가변 상태 (Mutex/RwLock)

~14 min · tauri, mutex, concurrency, rust

Level 0웹 관광객
0 XP0/56 lessons0/13 achievements
0/100 XP to next level100 XP to go0% complete
"command 여럿, 메모리 하나, 어쩌면 동시에. 락이 걔네가 서로 밟지 않게 막아주는 거야."

왜 그냥 못 바꾸나

managed state는 공유 참조를 쥐여주고, Rust는 공유 참조를 통한 변경을 금지해 — command 둘이 동시에 돌아서 데이터를 망칠 수 있으니까. 변경을 안전하게 허락하는 방법이 interior mutability야: 바뀌는 데이터를 Mutex<T>로 감싸. 바꾸려면 mutex를 lock()하는데, 락 가드가 떨어질 때까지 독점 접근을 줘. 락을 시도하는 다른 command는 차례를 기다려. 찢어진 쓰기 없음, 레이스 없음 — 강제돼.

락, 변경, 해제 — 빠르게

락은 가능한 한 짧게 들어. 락 걸고, 변경하고, 가드를 떨궈(보통 스코프 끝나면) 끝. 너무 오래 든 락은 앱 전체를 그 mutex 하나에 직렬화해. 쓰기보다 읽기가 훨씬 많은 state엔 RwLock이 여러 reader를 동시에 들이고 쓰기일 때만 막아 — 캐시랑 가끔 갱신되는 설정에 더 맞아.

async 함정 (또)

bridge 트랙의 Send 규칙 기억해: std::sync::Mutex 가드를 .await를 가로질러 들면 안 돼 — async command에서 컴파일 안 되고, 된다 쳐도 deadlock 위험이야. await 전에 가드를 떨구거나(락, 필요한 거 복사, 언락, 그다음 await) tokio::sync::Mutex 같은 async 인식 mutex를 써. 대부분 command엔 락-복사-언락 패턴이 제일 단순하고 빨라.

Code

command 사이에 살아남는 카운터·rust
use std::sync::Mutex;

// 가변 공유 상태: 카운터를 Mutex로 감쌈.
#[derive(Default)]
struct Counter {
    value: Mutex<i64>,
}

#[tauri::command]
fn increment(state: tauri::State<Counter>) -> i64 {
    // 락, 변경, 반환 — 가드는 줄/스코프 끝에서 떨어짐.
    let mut v = state.value.lock().unwrap();
    *v += 1;
    *v
}

pub fn run() {
    tauri::Builder::default()
        .manage(Counter::default())
        .invoke_handler(tauri::generate_handler![increment])
        .run(tauri::generate_context!())
        .expect("error");
}
락, 복사, 언락 — 그다음 await·rust
// async 안전 패턴: 락 안에서 복사해 내고, '그다음' await. std Mutex
// 가드를 .await 가로질러 절대 들지 마.
#[tauri::command]
async fn save_then_report(state: tauri::State<'_, Counter>) -> Result<i64, String> {
    let snapshot = { *state.value.lock().unwrap() }; // 여기서 락 떨어짐
    do_async_io(snapshot).await.map_err(|e| e.to_string())?;
    Ok(snapshot)
}

External links

Exercise

카운터를 만들어: Mutex<i64> 든 managed state랑, increment·get_count command. 프론트엔드 버튼 둘을 엮고, 클릭 사이에(그리고 컴포넌트 리렌더 사이에) 카운트가 유지되고 늘어나는지 확인해 — React state가 아니라 Rust 코어에 살아서. 보너스: Mutex를 빼면 왜 컴파일이 실패하는지 한 줄로 설명해.
Hint
increment: 락, *v += 1, *v 반환. tauri::State가 공유 참조라 interior mutability 없이는 Rust가 변경을 안 시켜줘서 Mutex가 필요해. Mutex 없이 공유 &i64에 *v += 1은 컴파일 에러야.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.