Search

C++ | 정말 기본적인 것이지만 가끔 놓지는 스택 유효 범위

Date
2024/12/17
category
C++
Tags
c++

1. 작업 중이던 코드

스레드를 관리하는 클래스를 만들고 있었다. 클래스 이름은 ThreadManager고 위 코드는 이 클래스의 메서드 중 하나인 Launch메서드다. 이 메서드를 구현하던 중 스택 유효 범위 관련 문제를 겪었다. 스택이 동작하는 방식은 크게 어렵지 않아서 이런 부분에서 실수할 것이라는 생각은 하지 못 했는데 아직 기본기가 부족한 것 같다. 코드의 맥락을 좀 더 설명해보면, Launch 메서드의 주요 동작은 callback을 수행하는 스레드를 만드는 것이다 . 멀티스레드 환경에서 수행돼서 3번 라인에서 락을 건다. _threadsstd::thread 타입의 스레드를 관리하는 std::vector다. 람다 함수는 callback을 호출한다. callback 호출 전후 코드는 thread local storage를 초기화하고 정리하는 코드다. 위 코드에서 무슨 문제가 발생할까?

2. 문제 분석

이 코드를 실행하면 callback을 호출하는 부분에서 프로그램이 죽는다. 그리고 죽는 것을 여러 번 시도해보면 에러 내용이 바뀔 때도 있다. 이런 상황이 발생하는 이유는 이 글의 제목에서 언급하듯이 스택의 유효 범위를 간과했기 때문이다. 스레드 생성 시 전달하는 람다 함수는 callback 파라미터의 참조를 캡처한다. 따라서 callback을 호출할 때 callback 파라미터는 유효해야 한다. 하지만 스레드를 생성하고 Launch 메서드는 종료되는데 그때 스택 프레임을 정리하면서 callback 파라미터를 정리한다. Launch의 스택 프레임이 정리되기 전에 생성한 스레드가 callback을 호출한다면 제대로 동작할 수도 있지만 보통 스레드가 생성되고 그 스레드가 시작되기까지 시간이 걸린다. 즉 위 상황에선 callback을 호출할 때 callback 파라미터는 이미 유효한 상태가 아닐 가능성이 매우 높다.

3. 수정 코드

람다가 callback을 캡처할 때 참조가 아닌 값을 캡처한다. 그러면 callback을 복사하게 되고 파라미터의 유효성은 람다의 callback에 영향을 주지 못 한다. 이런 스택 유효 범위 문제는 코드가 단순하면 쉽게 보이는데 약간 복잡해지면 은근히 실수하기 쉬운 것 같다. 스택의 데이터를 사용하는 것에 대한 경각심이 생겼다.