lock
이라는 아주 편한 thread-safe 키워드가 있다. lock(object)를 쓴 뒤 {} 코드 블럭을 감싸주면 그 안에있는 변수나 함수, 실행에 대한 접근은 thread 하나만이 접근할 수 있고 처리하게 된다.lock
과 비슷 한것이 lock_guard
다 완전히 같다고 하기엔 좀 다른데. 아무튼 내부적으로 생성자로 lock을 걸었다가 현재 스택프레임이 끝나면서 소멸자가 작동되고 소멸자에 unlock이 호출되는 방식이니 비슷하긴 하다.lock
이다. mutex 변수를 선언하고 lock
을 건다. unlock
을 적어두어야 하며, 까먹었을시 먹통이 되는 원인이 된다mutex m;
// 선언한 순간부터 lock이 걸린다.
{
...
std::lock_guard<std::mutex> lockGuard(m);
...
}
// defer_lock과 같이 호출시uniqueLock.lock()을 호출하기 전까지 lock 걸리는 것을 미룬다.
{
std::unique_lock<std::mutex> uniqueLock(m, std::defer_lock);
...
uniqueLock.lock()// 실제 락이 걸리는 위치
}
{
//이렇게 조건없이 뮤텍스를 넘기면 락가드마냥 바로 락걸린다.
std:unique_lock<std::mutex> uniqueLock(m);
}
spin: 돌다, 빙빙 돌다.
즉, 내가 lock을 가질 때 까지 계속해서 lock 접근을 시도한다. while
문에 atomic
구조체 변수를 이용하여 CAS(Compare-And-Swap)
류의 접근으로 계속해서 찔러본다.System.Thread
에 구현되어있다.class SpinLock{
private:
//이름만 봐도 알겠지만 원자성을 지키도록 도와주는 구조체
atomic<bool> _locked = false;
public:
void lock()
{
//CAS 방식이용하기 위한 변수
bool expected = flase;
bool desired = true;
while(_locked.compare_exchange_strong(expected, desired)== false){
expected = false;
}
}
void unlock(){
_locked.store(false);
}
}
_____
//thread에서 접근할 공유변수
int sum = 0;
//스핀 락 타입 설정
SpinLock spinLock;
//Thread에서 작동할 Add 함수
void Add(){
for(int i =0; i < 1000; i++{
// lock_guard를 이용해 spinlock을 건다.
// lock_guard 생성자에서 SpinLock클래스의 lock이 호출되고 이 lock은
// while문을 통해 lock권한을 얻을때까지 스핀한다.
lock_guard<SpinLock> guard(spinLock);
sum++;
}
}
void Sub(){
for(int i =0; i < 1000; i++{
// lock_guard를 이용해 spinlock을 건다.
// lock_guard 생성자에서 SpinLock클래스의 lock이 호출되고 이 lock은
// while문을 통해 lock권한을 얻을때까지 스핀한다.
lock_guard<SpinLock> guard(spinLock);
sum--;
}
}
int main()
{
Thread t1(Add);
Thread t2(Sub);
t1.join();
t2.join();
cout << sum << endl;//결과 0이 나와야 정상
}
https://woo-dev.tistory.com/164 | 쓰레드의 기본 활용법 with lock and conditional variable