[c++] 교착 상태(deadlock)

TNT·2024년 7월 28일
0

c++ 기초

목록 보기
11/17

교착 상태(膠着狀態) 또는 데드락(영어: deadlock)은 두 개 이상의 작업이 서로 상대방의 작업이 끝나기 만을 기다리고 있기 때문에 결과적으로 아무것도 완료되지 못하는 상태이다. 예를 들어 하나의 사다리가 있고, 두 명의 사람이 각각 사다리의 위쪽과 아래쪽에 있다고 가정한다. 이때 아래에 있는 사람은 위로 올라 가려고 하고, 위에 있는 사람은 아래로 내려오려고 한다면, 두 사람은 서로 상대방이 사다리에서 비켜줄 때까지 하염없이 기다리고 있을 것이고 결과적으로 아무도 사다리를 내려오거나 올라가지 못하게 되듯이, 전산학에서 교착 상태란 다중 프로그래밍 환경에서 흔히 발생할 수 있는 문제이다. 이 문제를 해결하는 일반적인 방법은 아직 없는 상태이다.
출처 위키피디아

코딩 할때 자주 나오는 발생할수있는 상태인데 두 스레드에서 서로를 참조하려고 기다리는 상황입니다.

예시로 보여주면 서로 락을걸고 a++ b++후에 서로에 스레드에 접근해서락 걸고 코드 진행을 하려고하는데
타이밍이 좋게 서로 걸린 상태라면 영원히 서로를 대기 한상태로 있는것이다.

이렇게 양쪽에서 서로 대시 상태가 발생하는걸 교착 상태라 라고한다.
게임 서버에서는 교착상태가 발생하면 증상이 생기는데

cpu 사용량이 현저히 낮아지거나 0% 에 가까워 진다
클라이언트가 서버를 이용할수 없고 패킷요청을해도 응답이 없다
그러면 이런 교착 상태가 발생할경우 원인을 찾아야하는데 찾기가 어렵다.

그러면 이러한 락을 사용될때 항상 규칙을 두고 사용하는것이 좋다.
여러 뮤텍스를 사용할 때 교착 상태를 예방하려면 각 뮤텍스의 잠금 순서를 먼저 둬야한다.
예시로 뮤텍스 A B C가 있다고 가정했을 때
코드 진행 순서가 A B C로 사용 된다고 가정

lock(A)
lock(B)
lock(C)
unlock(C)
unlock(B)
unlock(A)

순으로 스택 쌓듯이 사용하면 잠금순서를 잘 지켯기 때문에 사용할수있다.

만약 스레드 1에서 lock이 발생했는데 한번더 호출된다고 하면 이미 잠긴상태인걸 알고 unlock이 한번 발생해도 잠금상태가 안풀린다.

lock(A) //잠금
lock(A) //잠금상태인데 한번더 잠금
unlock(A) // 잠금을 풀지만 한번더 남았다.
unlock(A) // 완전히 풀린 상태

lock으로 최대한 막아서 서로에 교착을 피하면 좋은거 아닌가 라는 생각할수있는데
이러한 뮤텍스가 보호하는 범위가 커지면 스레드가 많더라고 하나일때와 차이가 없는수준이 될수도있다.

멀티 스레드를 쓰는 이유는 여러 cup 스레드가 각각 연산을 위해서 하는것데 그 장점이 죽어버리는것이다.

시리얼 병목

  1. num을 잠급니다.
  2. num에서 값을 하나 가져옵니다.
  3. num을 잠금 해제합니다.
  4. num이 소수인지 판별합니다.
  5. 소수면 primes를 잠급니다.
  6. primes에 소수를 넣습니다.
  7. primes를 잠금 해제합니다.

순으로 코드가 작성 되어있다고 가정 해보자

왼쪽에서 오른쪽으로 코드가 진행이 된다.
그러면 num을 잠그는 5~7까지의 구간이 잠긴상태이다.
그러면 이 구간에 들어가있는 스레드가 있으면 다른 스레드는 동시에 실행될수가 없다.
여러 cpu가있더라고 놀고 있게 되는것이다.


극단적으로 보자면 100개 가 있는 나머지 99개 스레드가 노는중인것이다.

cpu가 많아질수록 쉬는 빈공간이 남아있다.
하지만 코딩을 하면서 이런한 시리얼 병목을 없애기는 어렵다.

그래서 이런 락을 걸고 행동해야하는 코드 를 빨리 처리하고 풀어줘야하는데 만약 락을 걸고 디바이스를 읽는 것이나 이런 시간이 많이 소요 되는것은 최대한 빼줘야한다.
이러한 요소들이나 빼고 다시 락걸고 처리해주면 된다.
예시를 들자면

lock(A)
ReadFromDisk(x) // 시간이 많이 소요 되는 코드
unlock(A)

//////////////////////////////////////////////////

X = A.GetFoo();
unlock(A)
ReadFromDisk(X) // 락 풀고 처리후 다시 락 걸고 필요한 처리 시작
lock(A)
X.Somtiong();

여기서 소개 한 규칙이나 방식 제외하고 데드락 교착상태 이런한 문제들은 해결방식이 매우 다양하고 많기 때문에 한번쯤 찾아 보는것이 좋다.

참고 도서
게임서버 프로그래밍 교과서

profile
개발

0개의 댓글