스레드 수명

std::thread 수명 관리

스레드를 만들 수 있다는 설명만으로는 C++ 동시성 코드를 안전하게 쓸 수 없다. thread 객체가 joinable인지, join과 detach 중 무엇을 선택할지, 참조 인자가 얼마나 오래 살아 있는지, 공유 데이터에 mutex가 필요한지 확인해야 한다.

01

작업 함수 결정

스레드에서 실행할 함수와 인자가 복사될지 이동될지 참조될지 확인한다.

참조는 std::ref가 필요하다
02

스레드 생성

std::thread 생성 직후 별도 실행 흐름이 시작되고 thread 객체는 handle 역할을 한다.

실행 순서는 스케줄러에 달려 있다
03

공유 데이터 보호

여러 스레드가 같은 값을 읽고 쓰면 mutex, atomic, channel 같은 동기화가 필요하다.

data race는 undefined behavior다
04

join/detach 결정

결과를 기다리고 수명을 관리할 수 있으면 join, 독립 실행이면 detach의 수명 위험을 감수한다.

joinable thread 소멸자는 terminate를 부른다
05

예외와 종료 처리

스레드 함수 내부 예외를 잡아 전달 경로를 만들고 프로그램 종료 전 모든 스레드 상태를 정리한다.

예외는 스레드 경계를 자동으로 넘어오지 않는다
join
완료 대기 호출 스레드가 작업 종료를 기다리고 자원을 회수한다.
두 번 join할 수 없다
detach
독립 실행 thread 객체와 분리하지만 인자와 공유 자원의 수명 보장이 어려워진다.
마지막 선택에 가깝다
std::ref
참조 전달 기본 인자 복사를 피하고 참조를 넘길 때 명시한다.
원본이 스레드보다 오래 살아야 한다
mutex
공유 쓰기 보호 동시에 접근하는 데이터의 race를 막는다.
lock 순서와 deadlock도 본다

동시성 확인

joinable thread 객체가 소멸되기 전에 join 또는 detach 되었는지 확인한다.
참조 수명 스레드가 참조하는 지역 변수가 먼저 사라지지 않는지 본다.
race 검사 공유 데이터를 쓰는 모든 경로가 동기화되어 있는지 확인한다.