Rust 스마트 포인터 뮤텍스 공유(Arc)

mohadang·2023년 3월 4일
0

Rust

목록 보기
26/30
post-thumbnail

Rust에서는 메시지패싱 방식으로 여러 스레드가 메모리를 지향하지만 Mutex를 이용한 메모리 공유 기법 역시 지원한다.
다음과 같이 뮤텍스를 사용할 수 있다.

use std::sync::Mutex;

fn main() {
    let m = Mutex::new(5);

    {
    	// lock() 호출하여 락 획득
        // unwarp으로 가변 변수 획득
        // 다른 스레드가 패닉 상태의 락을 가지고 있을 경우 실패할 수 있다.
        // 그런 경우 아무도 락을 얻을 수 없게 되므로, 
        // unwrap을 택하여 그런 상황일 경우 이 스레드에 패닉을 일으킨다.
        let mut num = m.lock().unwrap();
        *num = 6;
    }

    println!("m = {:?}", m);
}

하지만 바로 사용하기 힙들다.

use std::sync::Mutex;
use std::thread;
fn main() {
    let counter = Mutex::new(0);
    let mut handles = vec![];
    for _ in 0..10 {
    	// 첫번째 쓰레드로 counter 소유권 이동
        // 두번째 쓰레드에서는 counter 소유권을 가져 오려고 하지만
        // error 발생, counter는 더이상 유효하지 않음
        let handle = thread::spawn(move || {
            let mut num = counter.lock().unwrap();
            *num += 1;
        });
        handles.push(handle);
    }
    for handle in handles {
        handle.join().unwrap();
    }
    println!("Result: {}", *counter.lock().unwrap());
}

counter 소유권이 첫번째 스레드로 이동 후 두번째 스레드에서 counter 접근시 소유권 에러가 발생한다.
소유권을 첫번째 스레드에 이동 시키지 않고 Rc를 이용해서 공유 가능할 수 있도록 하면 문제가 해결 될 것인가 ?

use std::rc::Rc;
use std::sync::Mutex;
use std::thread;
fn main() {
    let counter = Rc::new(Mutex::new(0));
    let mut handles = vec![];
    for _ in 0..10 {
        let counter = Rc::clone(&counter);
        let handle = thread::spawn(move || {
            let mut num = counter.lock().unwrap();
            *num += 1;
        });
        handles.push(handle);
    }
    for handle in handles {
        handle.join().unwrap();
    }
    println!("Result: {}", *counter.lock().unwrap());
}

그렇지 않다. 다음과 같은 에러를 발생 시킨다.
the trait `Send` is not implemented for Rc<Mutex<i32>>
Rc<Mutex<i32>>가 Send를 구현하지 않았기 때문에 쓰레드 안정성이 보장되지 않아 발생하는 에러이다.
이런 상황에서 사용 하고자 Arc라는 스레드 안정성을 가진 스마트 포인터가 있다.

use std::sync::{Mutex, Arc};
use std::thread;
fn main() {
    let counter = Arc::new(Mutex::new(0));
    let mut handles = vec![];
    for _ in 0..10 {
        let counter = Arc::clone(&counter);
        let handle = thread::spawn(move || {
            let mut num = counter.lock().unwrap();

            *num += 1;
        });
        handles.push(handle);
    }
    for handle in handles {
        handle.join().unwrap();
    }
    println!("Result: {}", *counter.lock().unwrap());
}

문제 없이 정상 실행된다.

Mutex 자체만으로 여러 스레드에서 캡처해서 사용할 수 없기에 mutex를 주고 받는 방식으로 코드 설계가 되어야 한다, 하지만 이렇게 데이터를 주고 받는다면 소통에 참여하는 스레드들 끼리 동기확가 되고 있다는 뜻이다.
개인적인 생각으로는 Rust에서 Mutex 자체만 사용하는 경우는 없을 것이라고 생각한다.
아마 Arc를 구현하기 위해 Mutex를 만든것이 아닐까 생각 든다.

profile
mohadang

0개의 댓글