scoped lock
개요
std::scoped_lock
은 C++17에 도입된 RAII 스타일의 뮤텍스 래퍼(wrapper)로, 하나 이상의 뮤텍스를 교착 상태(deadlock)의 위험 없이 안전하게 잠그기 위해 사용됩니다. 생성자에서 전달된 모든 뮤텍스를 잠그고, 소멸자에서 자동으로 해제하여 사용이 간편하고 안전합니다.
C++ 버전별 주요 키워드 도입 시기
- C++17:
std::scoped_lock
이 표준에 추가되었습니다.
내용 설명
여러 개의 뮤텍스를 다룰 때, 스레드마다 뮤텍스를 잠그는 순서가 다르면 교착 상태가 발생할 수 있습니다. 예를 들어, 스레드 1은 mutexA
를 잠근 후 mutexB
를 잠그려 하고, 스레드 2는 mutexB
를 잠근 후 mutexA
를 잠그려 하면 두 스레드 모두 영원히 기다리는 상태에 빠질 수 있습니다.
std::scoped_lock
은 내부적으로 교착 상태 방지 알고리즘(deadlock-avoidance algorithm)을 사용하여 인자로 전달된 모든 뮤텍스를 안전한 순서로 잠급니다. 이로 인해 개발자는 잠금 순서를 신경 쓸 필요 없이 여러 뮤텍스를 한 번에 잠글 수 있습니다.
이는 C++11의 std::lock()
함수와 std::lock_guard(mutex, std::adopt_lock)
를 함께 사용하던 복잡한 패턴을 대체하는 현대적이고 간결한 방법입니다.
예제 코드
#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
#include <chrono>
struct Account {
double balance;
std::mutex m;
};
void transfer(Account& from, Account& to, double amount) {
// std::scoped_lock을 사용하여 두 뮤텍스를 교착 상태 없이 잠급니다.
std::scoped_lock lock(from.m, to.m);
if (from.balance >= amount) {
from.balance -= amount;
to.balance += amount;
std::cout << "Transfer successful: " << amount << " from " << &from << " to " << &to << std::endl;
} else {
std::cout << "Transfer failed: Insufficient funds" << std::endl;
}
} // lock이 스코프를 벗어나면서 from.m과 to.m이 자동으로 해제됩니다.
int main() {
Account acc1{100.0};
Account acc2{50.0};
std::cout << "Initial balances: acc1=" << acc1.balance << ", acc2=" << acc2.balance << std::endl;
// 두 스레드가 서로 반대 방향으로 송금 (교착 상태 발생 가능성이 있는 시나리오)
std::thread t1(transfer, std::ref(acc1), std::ref(acc2), 20.0);
std::thread t2(transfer, std::ref(acc2), std::ref(acc1), 10.0);
t1.join();
t2.join();
std::cout << "Final balances: acc1=" << acc1.balance << ", acc2=" << acc2.balance << std::endl;
return 0;
}
실행 결과
Initial balances: acc1=100, acc2=50
Transfer successful: 20 from 0x... to 0x...
Transfer successful: 10 from 0x... to 0x...
Final balances: acc1=90, acc2=60
(실행 시점에 따라 송금 성공 메시지의 순서는 바뀔 수 있습니다.)
활용팁
- 두 개 이상의 뮤텍스 잠금: 두 개 이상의 뮤텍스를 동시에 잠가야 할 때 가장 먼저 고려해야 할 방법입니다.
- 가변 인자 템플릿:
std::scoped_lock
은 가변 인자 템플릿으로 구현되어 있어, 필요한 만큼의 뮤텍스를 인자로 전달할 수 있습니다. (std::scoped_lock lock(m1, m2, m3, ...);
) std::mutex
외 타입 지원:std::mutex
뿐만 아니라std::timed_mutex
,std::shared_timed_mutex
등Lockable
요구사항을 만족하는 모든 타입을 지원합니다.
'개발 > C++ (98,03,11,14,17,20,23)' 카테고리의 다른 글
Modern C++ : std::shared_timed_mutex (14) (0) | 2025.10.19 |
---|---|
Modern C++ : std::mutex (11, 14, 17) (1) | 2025.10.18 |
Modern C++ : std::thread (11) (0) | 2025.10.17 |
Modern C++ : std::exception (98, 11, 17) (0) | 2025.10.16 |
Modern C++ : std::weak_ptr (11) (1) | 2025.10.15 |
Modern C++ : std::shared_ptr (11, 17) (0) | 2025.10.14 |
Modern C++ : std::unique_ptr (11, 14) (0) | 2025.10.13 |
Modern C++ : std::format (20) (0) | 2025.10.12 |