[C++] recursive_mutex

Multi Thread 환경에서는 하나의 자원을 여러 thread가 동시에 접근할 수 있어서 그에 따른 문제가 발생할 수 있습니다.

그래서 Multi Thread 환경에서는 “상호배재”를 적용해야 합니다.

“상호배재”는 Mutex를 비롯하여 여러 방법으로 적용할 수 있는데, 이전 글에서 정리해 놓았습니다.

Semapore, Mutex, Spin-Lock 차이점

 

c++ 표준 라이브러리 에서는 recursive mutex 기능을 지원합니다.

mutex는 mutex lock을 실행한 thread가 자원의 점유 이후에 unlock를 해 주어야 합니다.

 

아래 그림을 보겠습니다.

 

먼저 thread1이 lock()을 통해 해당 자원을 점유하면, thread1이 unlock()을 하기 전까지 다른 thread는 해당 자원을 점유할 수 없습니다.

하지만 thread1이 unlock()를 통해서 자원을 놓아주면, 그 이후에는 thread2가 자원을 점유할 수 있게 됩니다.

 

이는 자기 자신에게도 마찬가지로 적용됩니다.

자기 자신이 한번 lock()을 걸면, unlock()으로 해제하기 전까지는 다시 lock()을 걸 수 없습니다.

 

그런데 만약 다음과 같이 재귀적으로 호출되는 함수가 있고, 그 내부에서 lock()을 하고 있다고 한다면 deadlock에 빠지고 말 것입니다.

#include <iostream>
#include <thread>
#include <mutex>

std::mutex g_i_mutex; int g_i; void function () {
std::lock_guard<std::mutex> lock(g_i_mutex); std::cout << "thread lock : " << g_i << '\n'; if( g_i > 0 ) { g_i--; function(); } } int main() { g_i = 5; std::thread t1(function); t1.join(); }

 

이를 위해서 c++ 표준 라이브러리에서는 “recursive_mutex” 기능을 제공하며, 이를 이용하면 해당 문제를 손쉽게 해결할 수 있습니다.

recursive_mutex를 이용하면 mutex lock을 재귀적으로 호출 할 수 있으며, 내부적으로는 lock counting을 하여서 count number가 0가 되면 해당 자원을 놓아주게 됩니다.

 

Source code는 다음과 같습니다.

#include <iostream>
#include <thread>
#include <mutex>

std::recursive_mutex mut;
int g_i;

void function ()
{
  std::lock_guard <std::recursive_mutex> lock(mut);
  std::cout << "thread lock : " << g_i << '\n';
  if( g_i > 0 )
  {
    g_i--;
    function();
  }
}

int main()
{
  g_i = 5;
  std::thread t1(function);
 
  t1.join();
}

 

혹시나 source code 내부의 “lock_guard”가 궁금하시다면, 아래 글을 참고해 주세요.

c++ : lock_guard


reference.