std::unique_lock
std::lock_guard와 비슷하지만 더 많은 기능을 가지고 있다.
Example Code
#include <iostream>
#include <thread>
#include <chrono>
#include <mutex>
struct MInt
{
std::mutex mtx;
int num = 0;
};
void plus1(MInt& mi)
{
std::unique_lock<std::mutex> lck(mi.mtx);
mi.num++;
}
int main()
{
MInt mi;
std::thread t1(plus1, std::ref(mi));
std::thread t2(plus1, std::ref(mi));
t1.join();
t2.join();
std::cout << "num : " << mi.num << std::endl;
return 0;
}
std::lock_guard와 마찬가지로 unique_lock을 걸린 다음부터 크리티컬 섹션이 되고 스코프가 종료될 때 lock을 자동적으로 해제한다. 그렇다면 unique_lock은 왜 사용할까?라고 생각할텐데 unique_lock은 lock_guard보다 많은 기능을 가지고 있다.
cppreference에서 보면 lockguard는 constructor와 destructor만 정의되어있고, Copy와 Move또한 불가능한데 이는 매우 제한적인 용도로 사용될 수 있다라는 의미이다. 반면에 unique_lock은 그 밖에 여러 기능들을 포함하고 있다. 그 중에서 unique_lock의 가장 중요한 점은 Move가 가능하다는 것이다. 즉, unique_lock의 Move가 가능하다라는 뜻은 어떠한 함수의 파라미터로 보낼 수도 있고, return으로도 보낼 수 있다는 말이다.
Example Code
#include <iostream>
#include <thread>
#include <chrono>
#include <mutex>
struct MInt
{
std::mutex mtx;
int num = 0;
};
std::unique_lock<std::mutex> unlockTest(std::unique_lock<std::mutex> lck)
{
// 어떠한 조건하에 lock을 해제한 후 return 할 수 있다.
if (true)
{
lck.unlock();
}
return lck;
}
void plus1(MInt& mi)
{
std::unique_lock<std::mutex> lck(mi.mtx);
mi.num++;
lck = unlockTest(std::move(lck)); // 오직 move만 가능하므로 RValue로 바꿔준다.
}
int main()
{
MInt mi;
std::thread t1(plus1, std::ref(mi));
std::thread t2(plus1, std::ref(mi));
t1.join();
t2.join();
std::cout << "num : " << mi.num << std::endl;
return 0;
}
이러한 접근이 무엇이 특별하냐고 한다면 이는 개발자가 mutex lock을 리소스로 관리할 수 있게 만들어준다는 점이다. 쉽게 말해 스마트 포인터를 통해서 heap 메모리안에 생성된 오브젝트를 안전하게 관리할 수 있게 해준 것처럼 unique_lock을 사용하면 리소스 중에 하나인 mutex lock을 안전하게 관리할 수 있게 만들어준다.
그렇다면 언제 lock_guard를 사용하고 언제 unique_lock을 사용해야 하는가?
원칙은 언제나 lock_guard를 먼저 사용하고 unique_lock의 기능이 필요할 때 unique_lock을 사용하면 된다. 그 이유는 lock_guard는 unique_lock에 비해 (무시해도 될 정도지만) 더 가볍기도 하고 제한적인 기능만 가지고 있기 때문이다.
'C++ > Thread' 카테고리의 다른 글
[Thread] std::shared_mutex (0) | 2022.07.17 |
---|---|
[Thread] Deadlock, std::scoped_lock (0) | 2022.07.17 |
[Thread] std::mutex (0) | 2022.07.15 |
[Thread] Mutex(뮤텍스) (0) | 2022.07.15 |
[Thread] std::jthread (조이닝 쓰레드) (0) | 2022.07.13 |