운영체제

[게임 프로그래머 입문 올인원] 멀티쓰레드 프로그래밍 : 락 기초, 스핀락, 데드락

순정법사 2024.12.03

A. 락 기초

1. 락 기초

a. 시작하기전에...

1) 아토믹 복습

 

모든걸 아토믹으로 바꾸면 해결이 될까

 

원자적으로 묶어주는건 정수 하나! 정도 정말 많이 할 순 없음

 

2) stl 컨테이너의 앙탈

 

위를 실행시키면 크래시가 난다

이유는 벡터같은 stl 컨테이너들은 멀티스레드로 동시다발적으로 실행하면 무조건 크래시

 

동적으로 할당한 영역은 heap 에 배치되는데

멀티스레드에서는 동시다발적으로 사용하기 때문에 누가 값을 날려버려 크래시가 난다

 

 

이사비용을 줄이기위해서  reserve함수를 사용해 미리 확대해놓고 사용한다면 이상한 값이 나옴

하나의 주소를 여러명이 사용하고 있기 때문에 (덮어써짐) 그럼

 

따라서 위와같은 벡터를 사용한다면 락을 잘 사용해야함

 

b. 락이란?

일련의 코드드를 묶어줘서 다른 코드가 접근하지 못하게 하는 것 => 락

 

🌟 개념: 락은 공유 자원을 보호하기 위해 사용하는 도구

 

Mutex 키워드가 사용되면 락

Mutual exclusive 상호 배타적

 

 

위 코드를 mutex로 실행하면 자물쇠처럼 보호장치가 되어 제대로 실행된다

 

그렇다고 이렇게 락을 잡으면 무조건 끝인경우가 아님

 

만약 10개의 스레드가 있다고 하면, 1개의 스레드만 저길 통과할 수 있기 때문에 

싱글스레드를 쓰는것만큼 효율이 없음

 

또한  unlock을 까먹고 안하면 문제가 발생된다

 

이렇게 꼼꼼하게 짝을 맞춰주기

 

이렇게 위와같이 계속 하나하나짝을 맞추면 힘들기 때문에

새로 생긴 락가드가 있음

 

c. 락 가드

이렇게 래퍼클래스를 만들어주고

 

이렇게 감싸주면 된다

 

d. 유니크 락

처음에 만들어줄때 옵션을 하나 더 줄수 있음

직접적으로 락 시점을 뒤로 민다

 

 

둘 중 하나를 사용해 락가드를 하면 된다!

 

 

 

 


B. 스핀락

1. 스핀락 기초

a. 스핀락이란?

🌟 개념: 락을 얻기 위해 계속해서 확인하면서 대기하는 방식

 

  • 장단점:
    • 장점: 락이 금방 풀릴 경우 효율적이야(대기 시간이 짧으면).
    • 단점: 락이 오래 걸려 있다면 CPU를 낭비하게 돼.
  • 사용 예시:
    • 멀티코어 CPU에서 짧은 시간 안에 락을 해제할 것이 예상되는 경우.

 

b. 스핀락 실습

우리가 만든 락

 

실행시키면 어떻게 될까?

Reserve 안쓰면 크러시, 안쓰면 이상한 값 (락 없이 처음에 만든거랑 동일)

 

락의 역할을 전혀 못하고있음

이유는 스레드가 동시에 들어왓기 때문!

 

 

상호배타적이라는 코드가 박살난것임

 

그래서 위 ifelse코드를 실행해주는 compare_exchange_strong 이 있음

 

성공할때까지 돌아가고 expected값이 변경된다

 

스핀락 -> 무한루프를 돌면서 계속 스레드가 들어가려고 하는 것

 

 

 


c. 데드락

1. 데드락 기초

a. 데드락이란?

🌟 개념: 여러 스레드가 서로 자원을 잠그고 동시에 다른 자원을 기다리다가 영원히 대기 상태에 빠지는 현상

 

 

 

  • 조건: 데드락이 발생하려면 네 가지 조건이 동시에 만족해야 해.
    1. 상호 배제(Mutual Exclusion): 자원은 한 번에 한 스레드만 사용할 수 있어.
    2. 점유 대기(Hold and Wait): 스레드가 이미 자원을 점유하고 있으면서 추가 자원을 기다려.
    3. 비선점(No Preemption): 점유한 자원을 강제로 빼앗을 수 없어.
    4. 순환 대기(Circular Wait): 스레드들이 자원을 서로 기다리며 순환 구조를 이룸.
  • 비유:
    • A가 열쇠를 들고 비누를 기다리고, B가 비누를 들고 열쇠를 기다리면서 서로 교환하지 못하는 상황.
  • 방지 방법:
    • 자원을 정해진 순서대로 요청하거나, 일정 시간이 지나면 요청을 포기하도록 설계.

 

 

b. Mmorpg에서 나오는 오류 범위

데드락이 두번째 / uaf : 메모리 더럽혀진것

 

c. 표준 락가드

 

 표준에 있는 락가드를 사용해 알아서 풀어주도록 할 수 있음

 

이렇게 일정 부분만 락하도록 풀어줄수 있음

 

리턴까지 하고 소멸시키기 때문에 안전


만약 사용하게 된다면 이런식으로 사용하면 됨 

 

d. 서로 잡고있는 락가드

이런식으로 락가드가 두개 있다고 하고
두개를 만들어서 만번씩 실행

 

실행하면 데드락

 

조인 어딘가에서 대기를 하고있음

 

ㅇㅣ 멈춤 버튼을 누르면 스레드가 어디를 표시하는지 알 수 있음

 

 

확인하면 둘 다 todo에서 멈춰있는데

이 이유는 두개가 락 잡는 순서가 꼬여있어서 발생 (m1 <-> m2)

 

 

이렇게 순서만 맞춰주면 끝임..

 

버그가 터지면 고치기는 쉽지만, 예방하기는 쉽지 않음 (한 두번가지곤 버그가 나지 않아서)

 

락들 사이에서 락이 락을 또 잡을 수 있음

 

그래프 알고리즘과 비슷하다

 

순환하면 위와같이 크러쉬가 남

 

하여간 깊게 들어가면 서버쪽이기때문에 이정도까지만 알아두자!

 

 

 


출처 : https://www.inflearn.com/course/%EA%B2%8C%EC%9E%84-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8-%EC%9E%85%EB%AC%B8-%EC%98%AC%EC%9D%B8%EC%9B%90-rookiss#curriculum

 

[게임 프로그래머 입문 올인원] C++ & 자료구조/알고리즘 & STL & 게임 수학 & Windows API & 게임 서버

Rookiss | 어디부터 시작할지 막막한 게임 프로그래밍 입문자를 위한 All-In-One 커리큘럼입니다. C++, 자료구조/알고리즘, STL, 게임 수학, Windows API, 게임 서버 입문으로 이어지는 알찬 커리큘럼으로

www.inflearn.com