나만의 공부 노트
쓰레드 본문
spawn으로 새로운 스레드 생성하기
use std::thread;
use std::time::Duration;
fn main() {
thread::spawn(|| {
for i in 1..10 {
println!("hi number {} from the spawned thread!", i);
thread::sleep(Duration::from_millis(1));
}
});
for i in 1..5 {
println!("hi number {} from the main thread!", i);
thread::sleep(Duration::from_millis(1));
}
}
move 키워드를 사용하여 사용하는 값의 소유권을 클로저가 갖도록 강제하기
use std::thread;
fn main() {
let v = vec![1, 2, 3];
let handle = thread::spawn(move || {
println!("Here's a vector: {:?}", v);
});
handle.join().unwrap();
}
메세지 패싱을 사용하여 스레드 간에 데이터 전송하기
우리는 mpsc::channel 함수를 사용하여 새로운 채널을 생성합니다; mpsc는 복수 생성자, 단수 소비자 (multiple producer, single consumer) 를 나타냅니다.
use std::thread;
use std::sync::mpsc;
fn main() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let val = String::from("hi");
tx.send(val).unwrap();
});
}
채널의 수신 단말은 두 개의 유용한 메소드를 가지고 있습니다: recv와 try_recv 입니다. 우리는 수신 (receive) 의 줄임말인 recv를 사용하는 중인데, 이는 메인 스레드의 실행을 블록시키고 채널로부터 값이 보내질 때까지 기다릴 것입니다. 값이 일단 전달되면, recv는 Result<T, E> 형태로 이를 반환할 것입니다. 채널의 송신 단말이 닫히면, recv는 더 이상 어떤 값도 오지 않을 것이란 신호를 하는 에러를 반환할 것입니다.
Mutex<T>의 API
lock의 호출은 다른 스레드가 패닉 상태의 락을 가지고 있을 경우 실패할 수 있습니다. 그런 경우 아무도 락을 얻을 수 없게 되므로, unwrap을 택하여 그런 상황일 경우 이 스레드에 패닉을 일으킵니다.
여러분이 의심한 것처럼, Mutex<T>는 스마트 포인터입니다.
더 정확하게는, lock의 호출은 MutexGuard라고 불리우는 스마트 포인터를 반환합니다.
안타깝게도, Rc<T>는 스레드를 교차하면서 공유하기에는 안전하지 않습니다. Rc<T>가 참조 카운트를 관리할 때, 각각의 clone 호출마다 카운트에 더하고 각 클론이 버려질 때마다 카운트에서 제합니다. 하지만 그것은 다른 스레드에 의해 카운트를 변경하는 것을 방해할 수 없도록 확실히 하는 어떠한 동시성 기초 재료도 이용하지 않습니다. 이는 잘못된 카운트를 야기할 수 있습니다-결과적으로 메모리 누수를 발생시키거나 아직 다 쓰기 전에 값이 버려질 수 있는 교묘한 버그를 낳겠죠.
Atomic Reference Counting with Arc<T>
다행히도, Arc<T>가 바로 동시적 상황에서 안전하게 사용할 수 있는 Rc<T> 타입입니다.
Send를 사용하여 스레드 사이에 소유권 이전을 허용하기
Send 마커 트레잇은 Send가 구현된 타입의 소유권이 스레드 사이에서 이전될 수 있음을 나타냅니다. 거의 대부분의 러스트 타입이 Send이지만, 몇 개의 예외가 있는데, 그 중 Rc<T>도 있습니다: 이것은 Send가 될 수 없는데 그 이유는 여러분이 Rc<T> 값을 클론하여 다른 스레드로 복제본의 소유권 전송을 시도한다면, 두 스레드 모두 동시에 참조 카운트 값을 갱신할지도 모르기 때문입니다. 이러한 이유로, Rc<T>는 여러분이 스레드-안전성 성능 저하를 지불하지 않아도 되는 단일 스레드의 경우에 사용되도록 구현되었습니다.
Sync를 사용하여 여러 스레드로부터의 접근을 허용하기
Sync 마커 트레잇은 Sync가 구현된 타입이 여러 스레드로부터 안전하게 참조 가능함을 나타냅니다. 바꿔 말하면, 만일 &T (T의 참조자) 가 Send이면, 즉 참조자가 다른 스레드로 안전하게 보내질 수 있다면, T는 Sync합니다. Send와 유사하게, 기초 타입들은 Sync하고, 또한 Sync한 타입들로 전체가 구성된 타입 또한 Sync합니다.