1. CAS(Compare And Swap)
비교 후 교체, 경쟁 조건을 방지하기 위한 연산 방식.
(1) compare_exchange_strong ; atomic 클래스의 함수
커스텀 락을 만들 때 효과적인 함수.
bool expected = false;
bool desired = true;
if (_flag == expected)
{
_flag = desired;
return true;
}
else
{
expected = _flag;
return false;
}
expected는 예상되는 값(이전 값), desired는 변경되기를 원하는 값(결과 값)이다.
_flag를 체크해 경쟁 조건이 발생하지 않아 값이 이전과 변함이 없다면(expected) 결과 값으로 _flag의 값을 변경시키고 true를 반환한다.
아닐 경우에는 expected에 현재 값을 저장하고 false를 반환한다.
위의 함수를 사용하여 경쟁 조건을 방지할 수 있다.
(2) 문법
while (_flag.compare_exchange_strong(expected, desired) == false)
{
expected = false;
}
이 코드를 사용하여 결과가 true가 될 때 까지 코드를 동작시킬 수 있다.
단 이 함수에는, 결과가 false일 때 expected의 값을 desired로 변환시키는 동작이 포함되어 있기 때문에, 항상 expected의 값을 원래의 값으로 초기화시켜야 한다는 점에 주의해야 한다.
(3) 활용
class Lock
{
public:
void lock()
{
bool expected = false;
bool desired = true;
while (_flag.compare_exchange_strong(expected, desired) == false)
{
expected = false;
}
}
void unlock()
{
_flag = false;
}
private:
atomic<bool> _flag = false;
};
Lock m;
vector<int> v;
void Push()
{
for (int i = 0; i < 10000; i++)
{
std::lock_guard<Lock> lockGuard(m);
v.push_back(i);
}
}
int main()
{
thread t1(Push);
thread t2(Push);
t1.join();
t2.join();
cout << v.size() << endl;
}
새로 만든 mutex를 본따 만든 Lock 클래스를 이용하여 lock_guard를 테스트하기 위하여 lock 함수와 unlock 함수를 오버로딩한 코드이다.
값이 정상적으로 2만이 뜨는 것을 볼 수 있다.
2. 스핀 락(Spin Lock)
뮤텍스와 같은 락은 다른 스레드가 작업을 종료할 때까지 대기열에서 대기하는 방법을 이용한다.
하지만 스핀 락을 사용하면 다른 스레드는 작업중인 스레드가 종료할 때(unlock)까지 계속 플래그를 검사하며 대기한다.
(1) 장점
- 간단한 경우에 짧은 순간에 락을 잡고 풀어준다는 확신이 있을 때 스핀 락을 사용하는 것이 성능에 있어 더 효율적이다.
(락을 획득하는 데 소요되는 시간이 짧다)
- 컨텍스트 스위칭을 최소화하여 CPU의 성능을 확보할 수 있다.
* 컨텍스트 스위칭(Context Switching)
CPU에서 실행되는 프로세스/스레드를 다른 프로세스/스레드로 교체하는 작업.
성능 비용이 많이 든다.
(2) 단점
- 계속 플래그를 체크하며 대기하기 때문에(Busy-Waiting) CPU의 자원을 많이 점유한다.
- 데드락이 발생할 수 있다.
'서버 프로그래밍 > 멀티 스레드' 카테고리의 다른 글
1-8. 생산자-소비자 패턴, 이벤트와 조건 변수(Condition Variable) (0) | 2023.11.28 |
---|---|
1-7. 데드락(Deadlock) (0) | 2023.11.24 |
1-5. 락 (Lock), 뮤텍스(mutex), RAII 패턴, lock_guard (0) | 2023.11.24 |
1-4. 공유 자원과 경쟁 조건 (0) | 2023.11.23 |
1-3. 캐시, CPU 파이프라인, 스레드 경쟁 조건 (1) | 2023.11.23 |