멀티 쓰레딩에서 std::lock_guard는 왜 사용하는 걸까? 예시를 들어 설명하겠다.
멀티 쓰레드에서 lock을 잡을 때 아래와 같이 worker() 함수 안에서 lock을 잡는다.
#include <thread>
#include <mutex>
#include <iostream>
int counter = 0;
std::mutex counter_mutex;
void worker() {
counter_mutex.lock();
if (counter == 1) { counter += 10; }
else if (counter >= 10) { counter += 15; }
else if (counter >= 50) { return; }
else { ++counter; }
std::cout << std::this_thread::get_id() << ": " << counter << '\n';
counter_mutex.unlock();
}
int main() {
std::cout << __func__ << ": " << counter << '\n';
std::thread t1(worker);
std::thread t2(worker);
t1.join();
t2.join();
std::cout << __func__ << ": " << counter << '\n';
}
그런데 만일 lock()와 unlock() 사이에 다른 함수를 사용하고 이 함수가 예외를 호출한다면 unlock()이 제대로 호출이 안 될수도 있다. 그렇기 때문에 아래와 같이 std::lock_guard를 사용한다. std::lock_guard는 RAII(Resource Acquisition Is Initialization) 구조를 사용하기 때문에 객체 소멸 시점에 강제로 unlock()이 호출된다. 그러므로 위의 worker() 함수 종료 시점에 자연스럽게 unlock()이 호출된다.
#include <thread>
#include <mutex>
#include <iostream>
int counter = 0;
std::mutex counter_mutex;
void worker() {
std::lock_guard<std::mutex> lock(counter_mutex);
if (counter == 1) { counter += 10; }
else if (counter >= 10) { counter += 15; }
else if (counter >= 50) { return; }
else { ++counter; }
std::cout << std::this_thread::get_id() << ": " << counter << '\n';
}
int main() {
std::cout << __func__ << ": " << counter << '\n';
std::thread t1(worker);
std::thread t2(worker);
t1.join();
t2.join();
std::cout << __func__ << ": " << counter << '\n';
}
위와 같이 수정이 가능하다.
'프로그래밍 언어 > C++' 카테고리의 다른 글
멀티쓰레딩 - Condition Variable (0) | 2025.05.13 |
---|---|
멀티 쓰레딩 - try_lock (0) | 2025.05.13 |
싱글턴 패턴 적용 (0) | 2024.08.21 |
std::count_if (1) | 2024.07.23 |
사용자 정의 리터럴(literal) (1) | 2024.07.23 |