스레드 활용하기
러스트에서 스레드는 std::thread 모듈을 통해 관리됩니다. 기본적인 스레드 생성은 다음과 같습니다.
use std::thread;
use std::time::Duration;
// 새로운 스레드 시작
let child_thread = thread::spawn(|| {
for count in 1..10 {
println!("자식 스레드: 숫자 {}", count);
thread::sleep(Duration::from_millis(1));
}
});
// 메인 스레드 실행
for count in 1..5 {
println!("메인 스레드: 숫자 {}", count);
thread::sleep(Duration::from_millis(1));
}
// 메인 스레드가 먼저 종료되면 자식 스레드도 강제 종료됨
Join으로 스레드 동기화
join()을 호출하면 메인 스레드가 자식 스레드의 종료를 기다립니다.
let handle = thread::spawn(|| {
for count in 1..10 {
println!("자식 스레드: 숫자 {}", count);
thread::sleep(Duration::from_millis(1));
}
});
for count in 1..5 {
println!("메인 스레드: 숫자 {}", count);
thread::sleep(Duration::from_millis(1));
}
handle.join().unwrap(); // 자식 스레드 종료 대기
Move 클로저로 소유권 이전
스레드 간 데이터 공유를 위해 move 키워드를 사용해 소유권을 이동시킵니다.
let numbers = vec![10, 20, 30];
let handle = thread::spawn(move || {
println!("벡터 데이터: {:?}", numbers);
});
handle.join().unwrap();
// numbers 변수는 이제 사용 불가 (소유권 이동됨)
채널(Channel)을 통한 메시지 전달
러스트는 mpsc (Multi-Producer, Single-Consumer) 채널을 제공합니다.
use std::sync::mpsc;
// 채널 생성 (송신자 tx, 수신자 rx)
let (sender, receiver) = mpsc::channel();
thread::spawn(move || {
let message = String::from("안녕하세요");
sender.send(message).unwrap();
// message는 소유권이 이동되었으므로 더 이상 사용 불가
});
let received = receiver.recv().unwrap();
println!("수신 메시지: {}", received);
여러 값 전송하기
let (sender, receiver) = mpsc::channel();
thread::spawn(move || {
let messages = vec![
String::from("첫 번째"),
String::from("두 번째"),
String::from("세 번째"),
];
for msg in messages {
sender.send(msg).unwrap();
thread::sleep(Duration::from_secs(1));
}
});
// 수신자를 반복자(Iterator)로 사용
for msg in receiver {
println!("수신: {}", msg);
}
다중 송신자 구현
clone()을 통해 여러 송신자를 생성할 수 있습니다.
let (sender, receiver) = mpsc::channel();
let sender_clone = mpsc::Sender::clone(&sender);
// 첫 번째 송신자
thread::spawn(move || {
let data = vec!["A1", "A2", "A3"];
for item in data {
sender_clone.send(item.to_string()).unwrap();
thread::sleep(Duration::from_millis(500));
}
});
// 두 번째 송신자
thread::spawn(move || {
let data = vec!["B1", "B2", "B3"];
for item in data {
sender.send(item.to_string()).unwrap();
thread::sleep(Duration::from_millis(500));
}
});
// 모든 메시지 수신
for msg in receiver {
println!("수신: {}", msg);
}
Mutex<T>로 데이터 보호하기
뮤텍스(Mutex)는 상호 배제(mutual exclusion)를 제공하여 데이터 경쟁을 방지합니다.
use std::sync::Mutex;
let counter = Mutex::new(0);
{
let mut value = counter.lock().unwrap();
*value = 10; // 값 변경
}
// 락이 해제됨
println!("최종 값: {:?}", counter);
Arc<T>로 공유 소유권 구현
Arc(Atomically Reference Counted)는 스레드 안전한 참조 카운팅을 제공합니다.
use std::sync::{Arc, Mutex};
use std::thread;
let shared_counter = Arc::new(Mutex::new(0));
let mut thread_handles = vec![];
for _ in 0..10 {
let thread_counter = Arc::clone(&shared_counter);
let handle = thread::spawn(move || {
let mut count = thread_counter.lock().unwrap();
*count += 1;
});
thread_handles.push(handle);
}
for handle in thread_handles {
handle.join().unwrap();
}
println!("최종 결과: {}", *shared_counter.lock().unwrap());