(C++) 다양한 mutex, lock 중 뭘 써야하나.
그냥 락 거는 것 보다, 다음 API들을 사용하는게 좋다.
스코프를 벗어나면 자동으로 해제되는 lock을 걸기 위해서는 (since C++ 17 || boost)
1
2
3
4
5
#include <mutex>
std::mutex mutex1;
std::mutex mutex2;
std::scoped\_lock lock(mutex1, mutex2);
// lock.unlock();
이는 std::lock_guard
에 여러 mutex들을 한번에 lock할 수 있는 기능을 추가한 완전한 상위 호환 API다. mutex 하나 넘길 때도 퍼포먼스 걱정 안해도 된다고 함.
다양한 기능을 지원하는 unique_lock
https://github.com/CppKorea/CppConcurrencyInAction/wiki/Chapter-03,-Sharing-data-between-threads 근데 약간의 성능 패널티가 있다고 함.
충돌이 거의 없는 경우 lock을 거는 오버헤드가 적은 spinlock(atomic_flag)을 쓰자.
lock을 acquire하고 release하는건 syscall을 부르는 꽤 비싼 연산이다. spinlock은 변수 하나의 0, 1을 체크해서 자원이 점유되고 있는지를 체크하는 lock이다. 자원이 점유 중이면, 릴리즈될 때 까지 while돌면서 계속 체크한다. 따라서 충돌이 발생하지 않는 경우 CPU를 많이 소모할 수 있지만, 충돌이 드물게 발생하는 경우라면 spinlock을 사용하는게 속도에 도움이 될 수 있다.
std::atomic_flag
로 간단히 구현할 수 있다.
https://en.cppreference.com/w/cpp/atomic/atomic_flag
* std::atomic_flag와 std::atomic의 차이?
atomic\_flag.test\_and_set()
은 변수 test-and-set을 한 과정의 atomic operation으로 처리하기 때문에 spinlock을 구현하려면 atomic_flag를 사용하는게 좋다. atomic<bool>
은 if 체크면 체크만, 할당이면 할당만 원자적 연산을 보장해준다. 체크하면서 동시에 할당하는 것도 메서드로 지원하는 것 같기는 한데, 뭔가 spinlock으로 쓰라고 있는 건 아닌 듯. 그렇다고 atomic<bool>
이 쓸모 없는거냐 하면 그 것도 아닌게, 스레드 내부의 running을 나타내는 변수 등에 쓰기에 적합하다.