thread_shared_mutex
thread_shared_mutex (공유 뮤텍스)
shared_mutex는 여러 스레드가 공유 데이터를 동시에 접근하지 못하도록 보호하는 동기화 기본 요소예요. 일반 뮤텍스가 배타적 접근만 제공하는 것과 달리, shared_mutex는 공유(shared)와 배타적(exclusive) 두 가지 접근 수준을 제공해요. 이 페이지에서는 shared_mutex의 개념, 멤버 함수, 사용 예시를 설명할게요.
출처: cppreference
본문
<shared_mutex> 헤더에 정의되어 있으며, C++17부터 사용할 수 있어요. shared_mutex 클래스는 공유 데이터를 보호하는 동기화 기본 요소로, 여러 스레드가 동시에 접근하는 것을 막아줘요. 배타적 접근만 제공하는 다른 뮤텍스와 달리, shared_mutex는 두 가지 접근 수준을 가져요.
- 공유(shared): 여러 스레드가 같은 뮤텍스의 소유권을 공유할 수 있어요.
- 배타적(exclusive): 오직 한 스레드만 뮤텍스를 소유할 수 있어요.
한 스레드가 배타적 잠금(lock, try_lock)을 획득하면, 다른 스레드는 공유 잠금을 포함한 어떤 잠금도 획득할 수 없어요. 반대로 한 스레드가 공유 잠금(lock_shared, try_lock_shared)을 획득하면, 다른 스레드는 배타적 잠금을 획득할 수 없지만 공유 잠금은 획득할 수 있어요. 배타적 잠금이 어떤 스레드에도 획득되지 않은 경우에만 여러 스레드가 공유 잠금을 획득할 수 있어요. 하나의 스레드 내에서는 동시에 하나의 잠금(공유 또는 배타적)만 획득할 수 있어요.
공유 뮤텍스는 공유 데이터를 여러 스레드가 동시에 안전하게 읽을 수 있고, 다른 스레드가 읽거나 쓰지 않을 때만 한 스레드가 데이터를 쓸 수 있어야 하는 상황에서 특히 유용해요. shared_mutex 클래스는 SharedMutex 및 StandardLayoutType의 모든 요구 사항을 충족해요.
멤버 타입
| 멤버 타입 | 정의 |
|---|---|
native_handle_type (선택*) |
구현 정의(implementation-defined) |
멤버 함수
| (생성자) | 뮤텍스를 생성해요 (공개 멤버 함수) |
|---|---|
| (소멸자) | 뮤텍스를 소멸해요 (공개 멤버 함수) |
operator= [deleted] |
복사 대입이 불가능해요 (공개 멤버 함수) |
| 배타적 잠금 | |
lock |
뮤텍스를 잠그고, 사용할 수 없으면 블록해요 (공개 멤버 함수) |
try_lock |
뮤텍스 잠금을 시도하고, 사용할 수 없으면 반환해요 (공개 멤버 함수) |
unlock |
뮤텍스 잠금을 해제해요 (공개 멤버 함수) |
| 공유 잠금 | |
lock_shared |
공유 소유권을 위해 뮤텍스를 잠그고, 사용할 수 없으면 블록해요 (공개 멤버 함수) |
try_lock_shared |
공유 소유권을 위해 뮤텍스 잠금을 시도하고, 사용할 수 없으면 반환해요 (공개 멤버 함수) |
unlock_shared |
공유 소유권의 뮤텍스 잠금을 해제해요 (공개 멤버 함수) |
| 네이티브 핸들 | |
native_handle |
구현 정의 네이티브 핸들 객체를 반환해요 (공개 멤버 함수) |
예제
아래 출력은 단일 코어 머신에서 생성된 결과예요. thread1이 시작되면 첫 번째 루프에 진입해 increment()를 호출한 다음 get()을 호출해요. 그러나 반환된 값을 std::cout에 출력하기 전에 스케줄러가 thread1을 잠들게 하고 thread2를 깨워요. thread2는 세 번의 루프 반복을 한 번에 실행할 충분한 시간을 가지게 되죠. 다시 thread1로 돌아와서, 아직 첫 번째 루프 반복 중이므로 카운터 값의 로컬 복사본인 1을 std::cout에 출력하고 나머지 두 번의 루프 반복을 실행해요. 멀티 코어 머신에서는 어떤 스레드도 잠들지 않으므로 출력이 오름차순으로 나올 가능성이 더 높아요.
#include <iostream>
#include <mutex>
#include <shared_mutex>
#include <syncstream>
#include <thread>
class ThreadSafeCounter
{
public:
ThreadSafeCounter() = default;
// Multiple threads/readers can read the counter's value at the same time.
unsigned int get() const
{
std::shared_lock lock(mutex_);
return value_;
}
// Only one thread/writer can increment/write the counter's value.
void increment()
{
std::unique_lock lock(mutex_);
++value_;
}
// Only one thread/writer can reset/write the counter's value.
void reset()
{
std::unique_lock lock(mutex_);
value_ = 0;
}
private:
mutable std::shared_mutex mutex_;
unsigned int value_{};
};
int main()
{
ThreadSafeCounter counter;
auto increment_and_print = [&counter]()
{
for (int i{}; i != 3; ++i)
{
counter.increment();
std::osyncstream(std::cout)
<< std::this_thread::get_id() << ' ' << counter.get() << '\n';
}
};
std::thread thread1(increment_and_print);
std::thread thread2(increment_and_print);
thread1.join();
thread2.join();
}
가능한 출력:
123084176803584 2
123084176803584 3
123084176803584 4
123084185655040 1
123084185655040 5
123084185655040 6
같이 보기
shared_timed_mutex (C++14) |
공유 상호 배제 기능을 제공하고 타임아웃이 있는 잠금을 구현해요 (클래스) |
|---|---|
shared_lock (C++14) |
이동 가능한 공유 뮤텍스 소유권 래퍼를 구현해요 (클래스 템플릿) |
unique_lock (C++11) |
이동 가능한 뮤텍스 소유권 래퍼를 구현해요 (클래스 템플릿) |