c++ std::mutex
std::mutex C++11
C++11 에서std::thread
가 등장하면서 std::mutex
가 추가되었다.
std::mutex클래스는 여러 스레드가 동시에 액세스하는 공유 데이터를 보호하는 데 사용할 수 있는 동기화 기본 요소다.mutex는 독점적이고 비재귀적인 소유권 의미 체계를 제공한다:
lock
이나try_lock
을 성공적으로 호출한 스레드는mutex
를unlock
이 호출 될 때까지 소유 한다.- 하나의 스레드가 mutex를 소유하면 다른 스레드들은
lock
을 호출하면block
되고,try_lock
을 호출하면false
를 반환한다. - 스레드가
lock
또는try_lock
을 호출하기 전에 mutex를 소유하고 있으면 안된다.
lock, unlock
아래 그림과 같이 사용할 수 있다. 실제 해당되는 변수와 직접적인 관계가 없다. mutex 객체를 생성하고lock
으로 권한을 획득하고 공유되는 데이터에 접근한다.
데이터에 관련된 작업을 마친 후에는 unlock
을 호출해야 다른 thread가 접근 할 수 있다.
try_lock
try_lock
메서드는 lock
메서드와는 다르게 return
값으로 현재 자원이 사용중인 아닌지 확인 할 수 있다.
Example
NOTE_ std::mutex는 일반적으로 바로 접근하지 못한다. std::unique_lock, std::lock_guard 아니면 std::scoped_lock을 사용하여 자원에 lock을 걸어주는 것이 더 exception-save한 방식이다.
std::lock_guard
-
기본으로 제공하는
lock
이나try_lock
을 사용했을 때 unlock하지 않는 실수를 할 수 가 있는데 이때 해결을 도와주는 친구가std::lock_guard
이다. -
unlock
을 하기 전에 예외가 발생한다면unlock
되지 않는 경우도 안전하게unlock
시켜준다.
std::lock_guard
는 mutex를 소유하고 있는 코드 블럭의 기간 동안 RAII-style 매커니즘을 제공하는 mutex wrapper다.
NOTE_ RAII (Resource Acquistion Is Initialization)-style은 객체가 실제 사용되는 영역을 벗어나면 자원을 해제해주는 기법을 고려하여 설계하는 방법이다.
Example
Result
std::unique_lock
-
std::unique_lock
은lock_guard
의 동작을 조금 더 확장한 것이다. -
RAII특성을 잃지 않으면서도 생성 시
lock
을 시키지 않고 특정 시점에lock
시킬 수 있다. -
std::unique_lock
은 주로 두개 이상의 mutex를 사용할 때 deadlock 에 빠지지 않고 mutex를 잘unlock
할 수 있도록 사용한다. -
생성자에 인자로 mutex객체만 넘겨준다면 생성 시에
lock
이 걸리게된다. 만약 생성자에 mutex와 함께std::defer_lock
,std::try_to_lock
,std::adopt_lock
을 같이 넣어주게 되면 초기 상태를 다르게 세팅 할 수 있다.-
std::defer_lock
:lock
이 걸리지 않으며 잠금 구조만 생성된다.std::lock()
함수로lock
할 수 있다. -
std::try_to_lock
:lock
이 걸리지 않으며 잠금 구조만 생성된다. 내부적으로try_lock()
을 호출해서 소유권을 가져 오며 실패 시 false를 반환한다.lock.owns_lock()
등의 코드로 자신이lock
을 할 수 있는지 확인이필요하다. -
std::adopt_lock
:lock
이 걸리지 않으며 잠금 구조만 생성된다. 현재 호출된 블럭의 스레드가 mutex의 소유권을 가지고 있다고 가정한다. (사용하려는 mutex 객체가 lock 되어 있는 상태여야 함) 이미lock
이 된 후 unlock을 하지 않더라도unique_lock
으로 unlock 가능하다.
-
Example
위 예제는 두개의 mutex 객체를std::defer_lock
으로 lock으로 초기화 하지 않고 한번에 std::lock()
으로 동시에 lock을 걸어 deadlock
이 걸리지 않게 된다.
만약 std::defer_lock
을 같이 넘겨주지 않으면 unique_lock
생성 시 바로 lock
으로 걸리기 때문에 deadlock
이 발생한다.