Post

[RUST] 러스트 프로그래밍 공식 가이드(제2판) 16장 요약

겁 없는 동시성

  • 소유권과 타입 검사를 지렛대 삼음으로써, 많은 동시성 에러가 컴파일 타임 에러가 됨

스레드를 이용하여 코드를 동시에 실행하기

  • 스레드 : 프로그램 내에서 동시에 실행되는 독립적인 부분들을 실행하는 기능

spawn으로 새로운 스레드 생성하기

  • 새로운 스레드를 생성하기 위해서는 thread::spawn 함수를 호출하고 여기에 새로운 스레드에서 실행하고 싶은 코드가 담긴 클로저를 넘김
  • 메인 스레드가 완료되면 생성된 모든 스레드는 실행이 종료되었든 혹은 그렇지 않든 멈추게 됨
  • thread::sleep 의 호출은 스레드의 실행을 강제로 잠깐 멈추게 하는데, 다른 스레드는 실행될 수 있도록 함

join 핸들을 사용하여 모든 스레드가 끝날 때까지 기다리기

  • thread::spawn의 반환 타입인 JoinHandle은 자신의 join 메서드를 호출하면 해당 스레드가 끝날 때 까지 기다림

스레드에 move 클로저 사용하기

  • thread::spawn 은 새 스레드에서 클로저를 실행하는 함수인데, 이 클로저가 외부 변수를 캡처할 경우 메인 스레드의 생명주기와 달라 외부 변수가 더 이상 유효하지 않을 수 있는데 이를 해결하기 위해 move 클로저를 사용하여 외부 변수의 소유권을 클로저로 이동시키며 thread::spawn(move || ...) 와 같이 사용됨

메시지 패싱을 사용하여 스레드 간 데이터 전송하기

  • 메시지 패싱이란 스레드 간 데이터를 직접 공유하지 않고, 메시지를 주고받는 방식으로 통신하는 방법을 말함
  • 채널 : 한 스레드에서 다른 쪽으로 데이터를 보내기 위한 일반적인 프로그래밍 개념
    • 메시지 보내기 동시성을 달성하기 위해 러스트 표준 라이브러리는 채널(channel) 구현체를 제공함
    • 송신자(tx, transmitter)와 수신자(rx, receiver)로 구성
    • mspc(multiple producer, single consumer) 는 복수 생산자와, 단일 소비자를 나타내며 mpsc::channel 함수는 튜플을 반환하는데 첫번째 요소는 송신 단말, 두번째 요소는 수신 단말을 나타냄 ((tx, rx))
    • send 메서드 : 송신자가 데이터를 채널에 보낼 때 사용하며 Result<T,E> 타입을 반환함 (수신자가 닫혀있으면 에러 반환)
    • recv 메서드 : 수신자가 채널로부터 데이터를 기다리고 받을 때 사용하며 Result<T,E> 타입을 반환함 (송신자가 닫히면 에러 반환)
    • try_recv 메서드 : 메시지가 있으면 즉시 반환하고, 없으면 Err 를 반환하며 Result<T,E> 타입을 반환

채널과 소유권 이동

  • 채널(mpsc::channel)로 값을 보낼 때 send 메서드는 소유권을 가져가는데, 이는 send(val) 를 호출한 뒤 보내진 val 을 양쪽 스레드에서 동시에 접근할 수 있다면 데이터 경쟁이 발생할 수 있기 때문에 러스트는 이런 위험을 컴파일 타임에 차단

공유 상태 동시성

뮤텍스

  • 뮤텍스(mutex)는 상호 배제(mutual exclusion)의 줄임말로, 뮤텍스에서는 한 번에 하나의 스레드만 데이터 접근을 허용함
  • 뮤텍스의 두 가지 규칙
    1. 데이터를 사용하기 전에는 반드시 락을 얻는 시도를 해야 함
    2. 뮤텍스가 보호하는 데이터의 사용이 끝나면 반드시 언락을 해야 다른 스레드들이 락을 얻을 수 있음
  • Mutex에는 **교착 상태**를 생성할 위험성이 있음
    • 교착상태 예시
      1
      2
      3
      
        테이블에 숟가락과, 포크가 있고 숟가락, 포크를 모두 얻어야 식사를 할 수 있는데,
        두 사람이 각각 숟가락과 포크를 하나씩 나눠 가져간 경우,
        테이블에는 아무것도 존재하지 않아 무한히 대기하는 상황이 발생됨
      

Mutex의 API

  • Mutex는 스마트 포인터이며, 연관 함수 `new` 를 사용하여 만들어짐
  • 뮤텍스 내의 데이터에 접근하기 위해서는 lock 메서드를 사용하여 락을 획득
  • 락을 보유 중인 스레드가 패닉을 발생하면, 그 락은 손상 상태가 되어 이후의 lock 호출은 Err 를 반환
  • lockMutexGuard 라는 스마트 포인터를 반환하는데 이 타입은 Deref를 구현하여 *guard 로 내부 값 접근이 가능하며 또한 Drop도 구현되어 있어 스코프를 벗어나면 자동으로 Drop 되어 락이 해제됨

Arc를 이용한 아토믹 참조 카운팅

  • Arc<T>는 스레드 간 안전하게 공유 가능한 Rc<T> 같은 타입
  • “A”는 Atomic(원자적) 을 의미하며, 참조 카운트를 원자적 연산으로 증가/감소시켜 여러 스레드에서 동시에 접근해도 데이터 경쟁 없이 안전함
This post is licensed under CC BY 4.0 by the author.