Rust 스마트 포인터 2

mohadang·2023년 1월 23일
0

Rust

목록 보기
15/30
post-thumbnail

쓰레드간 공유(Mutex)

Mutex는 보통 스마트 포인터가 보유하는 컨테이너 데이터 구조로서, 데이터를 가져오거나 안에 있는 것에 대한 변경 가능한 또는 불가능한 참조를 할 수 있게 해준다.

잠긴 참조를 통해 OS가 동시에 오직 하나의 CUP만 데이터에 접근 가능하도록 하고, 원래 스레드가 끝날 때까지 다른 스레드들을 막음으로써 참조 남용을 방지한다.

Mutex는 여러 개의 CPU 스레드가 같은 데이터에 접근하는 걸 조율하는 방법

use std::sync::Mutex;

struct Pie {
    value: i32,
}
impl Pie {
    fn up(&mut self) {
        self.value += 1;
    }
}

fn main() {
    let heap_pie = Mutex::new(Pie{value: 0});
    let ref_pie = heap_pie.lock().unwrap();
    println!("val : {}", ref_pie.value);
}

쓰레드간 공유(Arc)

스레드 안정성을 가진 참조 카운트 증가 방식을 사용한다는 걸 제외하고는 Rc와 동일
동일한 Mutex에 다수의 참조를 가질 때 종종 사용

스마트 포인터 조합

Rc<Vec<Foo>>

  • Vec에 대한 스마트 포인터, 변경 불가능한 얕은 복사 가능

Rc<RefCell<Foo>>

  • 복수의 스마트 포인터가 동일한 Foo 구조체를 변경 가능/변경 불가 참조 가능

Arc<Mutex<Foo>>

  • 복수의 스마트 포인터가 임시의 변경 가능한 또는 불가능한 참조를 CPU 스레드 독점 방식으로 잠금
use std::cell::RefCell;
use std::rc::Rc;

struct Pie {
    value: i32,
}
impl Pie {
    fn up(&mut self) {
        self.value += 1;
    }
}
struct Basket {
    // Rc : 여러 스마트 포인터 접근 가능
    // RefCekk : 참조이기에 항상 유효한 메모리
    pie: Rc<RefCell<Pie>>
}
impl Basket {
    fn add(&self) {
        let mut p = self.pie.borrow_mut();
        p.up();
    }
}

fn main() {
    // 컨테이너와 다른 생명 주기를 가지기 위해 참조(Ref) 대신 얕은 복사
    let pie = Rc::new(RefCell::new(Pie {value: 0}));
    
    let ferris = Basket {
        pie: pie.clone(),//Rc
    };
    let sarah = Basket {
        pie: pie.clone(),//Rc
    };

    ferris.add();
    sarah.add();
    let p = pie.borrow();//RefCell, `.` 사용시 역참조는 컴파일러가 알아서 추가
    println!("{}", p.value);
}

내부 가변성 패턴

이런 조합이 많이 포함된 주제가 있다.
내부 데이터를 변경하기 위해 immutable한 데이터 유형(복수의 smart pointer가 소유할 수 있음)을 사용한다.
이를 Rust에서는 내부 가변성 패턴이라고 한다.
이는 Rust의 컴파일 타임 체크와 동일 수준의 안전성으로 런타임의 메모리 사용 규칙을 변경할 수 있는 패턴이다.

profile
mohadang

0개의 댓글