| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
Tags
- Strongly Connected Component
- ccw 알고리즘
- trie
- 트라이
- Behavior Design Pattern
- Express.js
- 강한 연결 요소
- Github
- 그래프 탐색
- Prisma
- LCA
- 2-SAT
- R 그래프
- 비트필드를 이용한 dp
- PROJECT
- 이분 탐색
- localstorage
- 비트마스킹
- 분리 집합
- 게임 서버 아키텍처
- Binary Lifting
- 벨만-포드
- SCC
- Spin Lock
- DP
- Lock-free Stack
- map
- JavaScript
- 최소 공통 조상
- 자바스크립트
Archives
- Today
- Total
dh_0e
[C++/Game Server] Spin Lock, Volatile 변수 본문
Spin Lock
- Lock 메커니즘 중 하나로, 스레드가 lock을 얻을 때까지 계속해서 루프를 돌며 기다리는(spin) 방식
- 멀티스레드 환경을 제대로 이해하고있는지 확인하기 위해 면접에서 주로 묻는 개념
class SpinLock
{
public:
void lock() {
while (_locked) {
}
_locked = true;
}
void unlock() {
_locked = false;
}
private:
volatile bool _locked = false;
};
- 위 코드의 lock() 함수를 보면 _locked가 false가 될 때까지 while 문으로 spin하다가 lock이 풀리면 즉시 lock을 점유하는 Spin Lock의 방식을 확인할 수 있음
- 하지만 위 코드로 멀티스레드 환경을 실행해보면 스레드가 겹쳐서 결과값이 제대로 안 나옴
- lock이 풀려있는지 확인하는 while문과, lock을 획득하는 제어문이 분리되어 있어서 while문을 동시에 통과한 두 스레드 t1, t2가 있을 시에 동시에 lock을 걸어주면서 문제가 발생
이를 해결하기 위해 atomic으로 묶어주는 함수를 CAS(Compare-And-Swap) 계열 함수라고 함
CAS(Compare-And-Swap) 함수
//cAS 의사(pseduo) 코드
if (_locked == expected)
{
_locked = desired;
return true;
}
else {
expected = _locked;
return false;
}
- 동기화 원자 연산(atomic operation) 중 하나로, 위에서 발생한 문제를 해결하기 위해 lock이 풀려있는지 확인과 lock 획득을 동시에 실행할 수 있게끔 해주는 함수로 atomic에 포함되어 있음

class SpinLock
{
public:
void lock() {
bool expected = false;
bool desired = true;
while (_locked.compare_exchange_strong(expected, desired) == false) {
expected = false;
}
}
void unlock() {
_locked.store(false);
}
private:
atomic<bool> _locked = false;
};
- compare_exchange_strong() 함수는 CAS 수도 코드처럼 _locked가 expected(false)이면 _locked를 획득하는 로직을 동시에 가지고 있음
- std::mutex도 더 복잡하긴 하지만 CAS 기반 동기화 로직을 포함하고 있음
Volatile 변수
- 맨 위 코드에 _locked를 선언할 때 앞에 붙은 키워드로, C/C++에서 컴파일러에게 해당 변수는 언제든 외부에서 변경될 수 있으니, 최적화를 하지 말고 항상 메모리에서 읽고 쓰도록 명령하는 키워드
int a = 1;
a = 2;
a = 3;
a = 4;
- 위 예시 코드를 컴파일한 어셈블리어로 바꾸는 과정에선 컴파일러가 최적화를 해서 앞 과정을 생략하고 a를 4라는 값으로만 기억함
volatile int a = 1;
a = 2;
a = 3;
a = 4;
- 키워드에 volatile을 추가하면 a=1, a=2, a=3 모두 쓸데없지만 최적화하지 않고 모두 메모리에 값을 저장하는 작업을 수행하게 됨
volatile bool running = true;
void thread1() {
while (running) {
// do something
}
}
void thread2() {
running = false;
}
- 다음과 같은 예시에서도 running 변수를 volatile로 선언하지 않는다면, thread1이 running을 레지스터에 저장해놓고 바뀌지 않는다고 착각할 수 있음
- 이를 토대로 최적화한다면 running의 값을 사용할 때마다 메모리에서 직접 읽어오지 않아, thread2가 running 값을 바꿔도 thread1은 감지하지 못함
- 하지만 volatile 변수로 선언해줌으로써 running을 항상 메모리에서 읽어오며 thread2로 값이 변경되는 것을 감지할 수 있음
'C++ > Game Server' 카테고리의 다른 글
| [C++/Game Server] 동기화 방식과 메모리 정책 (memory_order) (1) | 2026.02.04 |
|---|---|
| [C++/Game Server] future, promise, packaged_task (1) | 2025.08.08 |
| [C++/Game Server] Spin Lock, Event Lock, Condition Variable (6) | 2025.08.05 |
| [C++/Game Server] mutex, atomic, lock_guard, unique_lock (2) | 2025.07.24 |
| [C++/Game Server] Thread (1) | 2025.07.23 |