#include <thread>
#include <atomic>
#include <mutex>
class SpinLock
{
public:
void lock()
{
// CAS(Comapre-And-Swap)
bool expected = false;
bool desired = true;
while (false == bLocked.compare_exchange_strong(expected, desired))
{
expected = false;
}
}
void unlock()
{
bLocked.store(false);
}
private:
atomic<bool> bLocked = false;
};
int32 sum = 0;
SpinLock spinlock;
mutex m;
void Add()
{
for (int i = 0; i < 100000; i++)
{
lock_guard<SpinLock> guard(spinlock);
sum++;
}
}
void Sub()
{
for (int i = 0; i < 100000; i++)
{
lock_guard<SpinLock> guard(spinlock);
sum--;
}
}
int main()
{
thread t1(Add);
thread t2(Sub);
t1.join();
t2.join();
cout << sum << endl;
}
스핀락을 활용하기 위해서는 lock() 실행 시, 자원을 획득하는 스레드를 하나만 넘겨주고 다른 스레드들은 접근할 수 없도록 while()에 대기시킬 수 있어야 합니다. 하지만 아래와 같은 코드는 atomic하게 동작하지 않기 때문에, 이를 처리할 방법이 필요합니다.
while(bLocked)
{
}
// 데이터영역 boolean
bLocked = true;
간단한 코드이지만, 스레드는 언제나 병렬 작업을 실시하기 때문에 bLcoked이 false인 경우 동시에 while문을 빠져나가면서 [bLocked = true] 코드로 접근할 수 있습니다. 이를 방지하기 위해 atomic 변수 지원 함수 중 CAS(Compare-And-Swap)을 지원해주는 compare_exchange_strong() 함수를 사용합니다.
함수 내부는 다음과 같이 작동한다고 볼 수 있습니다.
bool expected = false;
bool desired = true;
if (bLocked == expected)
{
bLocked = desired;
return true;
}
else
{
expected = bLocked; // CAS 실패 시 expected 값은 실제 메모리 값으로 갱신됨
return false;
}
메모리 값(bLocked)이 expected와 같은 지 원자적으로 비교하고, 같으면 desired로 교체하면서 true를 반환, 다르면 교체 실패로 expected를 현재 메모리값으로 자동 업데이트 하는 구조입니다. 해당 연산이 원자적으로 이뤄지기 때문에, while문을 빠져나와 true로 값이 입력되는 상황이 완전히 동시에 처리되도록 할 수 있게 됩니다.
하지만 아시다시피, while문을 결국 실행한다는 것은 불필요한 스레드에게 작업을 할당하는 것과 다름 없습니다(CPU 작업이 계속 진행됨). 이런 경우 sleep을 활용하면 효과적일 수 있습니다.
class SpinLock
{
public:
void lock()
{
// CAS(Comapre-And-Swap)
bool expected = false;
bool desired = true;
while (false == bLocked.compare_exchange_strong(expected, desired))
{
expected = false;
this_thread::sleep_for(std::chrono::milliseconds(100));
// this_thread::sleep_for(100ms);
// this_thread::yield(); == this_thread::sleep_for(0ms);
}
}
void unlock()
{
bLocked.store(false);
}
private:
atomic<bool> bLocked = false;
};'서버' 카테고리의 다른 글
| [Server] 데드락(DeadLock) (0) | 2025.03.17 |
|---|---|
| [Server] Lock(mutex) (0) | 2025.03.17 |
| [Server] atomic (0) | 2025.03.17 |
| [Server] 스레드 (0) | 2025.03.17 |











