티스토리 뷰

 모든 스레드 객체는 합류 가능이거나 합류 불가능이다. 여기서 말하는 합류는 join 을 사용할 수 있는 상태를 말한다. 합류 불가능 스레드는 다음의 목록이 존재한다.

  • 기본 생성된 std::thread

실행할 함수가 없이 생성된 객체는 바탕 실행 스레드와는 대응되지 않는다.

  • 다른 std::thread 객체로 이동된 후의 std::thread 객체

이동이 완료되면 기존의 스레드는 대응되는 스레드가 존재하지 않는다.

  • join 에 의해 합류된 std::thread

join 이 완료되면 대응되는 스레드가 존재하지 않는다.

  • detach 에 의해 탈착된 std::thread

스레드 객체와 바탕 스레드와의 연결이 끊어져 합류 불가능 상태가 된다.

 

문제점

 합류 가능성이 중요한 이유는 합류 가능 스레드소멸자가 호출되면 프로그램이 종료되기 때문이다. 예제를 통해 살펴보자.

constexpr auto tenMillion = 10'000'000;

bool doWork(std::function<bool(int)> filter,
            int maxVal = tenMillion)
{
   std::vector<int> goodVals;
   
   std::thread t([&filter, maxVal, &goodVals]
                 {
                   for (auto i = 0; i <= maxVal; ++i)
                   { if (filter(i)) goodVals.push_back(i); }
                 });

  auto nh = t.native_handle();
  ...
  
  if (conditionsAreSatisfied()) {
    t.join();
    performComputation(goodVals);
    return true;
  }
  
  return false;
}

 위의 코드에서 conditionsAreSatisfied() 함수가 true 를 반환하면 문제는 발생하지 않는다. 그러나 false 를 반환하는 경우에는 t 의 소멸자가 호출되어 프로그램이 종료된다. 왜 다른 방식으로 동작하지 않고 프로그램이 종료될까? 만약 프로그램이 종료되지 않는 경우를 살펴보자.

암묵적 join

 스레드의 소멸자가 스레드가 완료되기를 기다리는 방식이다. 합리적으로 보이지만 사실은 그렇지 않다. conditionsAreSatisfied() 가 이미 false 를 반환해서 함수가 종료되어도 마땅한 상황임에도 스레드가 종료되길 기다려야 하는 것은 합리적이지 않다.

암묵적 detach

 스레드가 실행중인 상태에서 false 를 반환하여 doWork 함수가 종료되었다고 가정해보자. doWork 가 종료되며 지역변수들도 함께 소멸된다. 문제는 위의 코드에서 스레드는 goodVals 라는 지역변수를 참조로 사용하고 있다. 그렇게되면 스레드는 소멸된 변수에 접근하게 되어 미정의 행동을 하게 되는데, 이를 디버깅하기란 매우 어려울 것이다.

결과적으로 두가지 경우 모두 적절하지 않으므로 프로그램을 종료하기로 결정되었다. 다행히도 우리는 RAII 방식을 사용하여 문제를 해결할 수 있다.

class ThreadRAII {
public:
  enum class DtorAction { join, detach };
  
  ThreadRAII(std::thread&& t, DtorAction a)
  : action(a), t(std::move(t)) {}
  
  ~ThreadRAII()
  {
    if (t.joinable()) {
      if (action == DtorAction::join) {
        t.join();
      } else {
        t.detach();
      }
    }
  }
  
  ThreadRAII(ThreadRAII&&) = default;
  ThreadRAII& operator=(ThreadRAII&&) = default;
  
  std::Thread& get() { return t; }
  
private:
  DtorAction action;
  std::thread t;
};

 

참고 서적

스콧 마이어스, Effective Modern C++
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함