RAII (Resoruce Acquisition is Initialization) 패턴은 자원의 할당과 해제를 자동화해주는 패턴입니다.
DB인증, 공유자원 등 여러 방면에서 활용될 수 있으며 코드의 안전성을 보장해줍니다.
스택에 할당된 메모리가 자동으로 해제되며 소멸자가 호출된다는 점을 이용한 패턴이며,
저는 최근 C++의 멀티스레드 프로그래밍을 공부하며 접하게 되었습니다.
Thread의 동기화를 제어하는 방식은 Atomic과 Lock등 여러 방법이 있습니다.
다만 Lock의 경우 lock, unlock이 set를 이루어 작동되어야합니다.
lock 이후 unlock이 이루어지지 않는 경우 무한한 대기상태에 빠지게 됩니다.
멀티스레드 환경에서는 이러한 문제를 LockGuard를 이용해 unlock을 보장합니다.
#include <mutex>
vector<int32> v;
mutex m; // mutual exclusive 상호배타적
// RAII 패턴 (Resource Acquisition is initialization)
// 생성자에서 잠그고, 소멸자에서 풀어주는 패턴
// DB연결이나 리소스접근에서 사용
template<typename T>
class LockGuard //wrapper class role
{
public:
LockGuard(T& m)
{
_mutex = &m;
_mutex->lock();
}
~LockGuard()
{
_mutex->unlock();
}
private:
T* _mutex;
};
void Push()
{
for (int32 i = 0; i < 10000; i++)
{
LockGuard<std::mutex> lockGuard(m); //lockGuard 객체 생성
v.push_back(i);
}
}
int main()
{
std::thread t1(Push);
std::thread t2(Push);
t1.join();
t2.join();
cout << v.size() << endl;
}
임의로 생성된 LockGuard 클래스입니다.Push함수내에서 생성되어 mutex변수를 포함하는 wrapper class 로서 작동합니다.함수내에서 생성된 이상 스택영역에 저장되어 Push함수가 실행종료됨고 동시에 파괴자를 호출하며 해제됩니다.
일일히 lock과 unlock을 선언하는 것보다 객체 생성에 부하가 주어지지만 안전한 코드가 작성하다는 장점이 있습니다.해당 LockGuard는 C++ 스탠다드에서 이미 제공중인 기능이며 스탠다드의 함수를 이용할때는 다음과 같습니다.
void Push()
{
for (int32 i = 0; i < 10000; i++)
{
std::lock_guard<std::mutex> lockGuard(m); //C++ 표준
v.push_back(i);
}
}
+) lockGuard 이외에도 lock의 실행시점을 미룰 수 있는 unique_lock등의 옵션을 가진 여러 lock 이 존재합니다.
https://en.cppreference.com/w/cpp/thread/unique_lock
'MultiThread' 카테고리의 다른 글
APC와 Alertable wait 상태에 대한 정리 (0) | 2021.12.29 |
---|---|
Reader Writer Lock 구현 (0) | 2021.12.13 |
기초적인 Lock Free Stack 구현 (0) | 2021.12.03 |
이벤트 방식 Lock 구현 (Condition Variable, Window API) (1) | 2021.11.04 |
CAS(Compare and Swap)와 SpinLock 구현 (0) | 2021.11.02 |