인프런 커뮤니티 질문&답변

y_y님의 프로필 이미지
y_y

작성한 질문수

[C#과 유니티로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버

DeadLock

멀티쓰레드와 관련해서 질문이 있습니다.

해결된 질문

작성

·

252

0

멀티쓰레드를 학습하게 되면서 나름대로 정리를 해보았는데요. 

멀티쓰레드 환경에서는 쓰레드가 공유하는 자원에 대한 일관성이 보장되어야 한다.

즉, 특정 쓰레드에서 공유 자원의 데이터를 변경하면 다른 쓰레드에서도 똑같이 변경된 데이터를 다뤄야한다.

이러한 문제를 해결하기 위해 쓰레드가 공유 자원에 접근하기 전 Lock을 걸고 들어가서 다른 쓰레드가 해당 자원에 접근하지 못하도록 막고, UnLock을 통해서 다른 쓰레드가 접근할 수 있게 해준다. 이 때 접근한 쓰레드는 변경된 공유 자원 데이터를 사용하게 된다. 이렇게 이해한게 맞는건가요 ? 

원자성이라는 개념을 이해하기를 하나의 작업을 처리할 때 수행되는 모든 과정들을 일련의 한 묶음으로 보고 이것은 마치 더이상 나누어지지 않는 것처럼 모두 수행되거나 모두 수행되지 않아야 한다.

그런데 Lock을 통해서 원자성을 구현한다고 이해하고 있는데 이게 맞는건지 궁금합니다... 

왜냐하면 Lock을 통해서 공유자원에 다른 쓰레드가 접근을 못하게 막는것은 맞지만 Unlock을 할 때까지 여러가지 작업을 할 수 있는데 그것은 원자성을 보장하지 않는 거 같다고 생각해서입니다.

답변 1

1

Rookiss님의 프로필 이미지
Rookiss
지식공유자

멀티쓰레드 환경에서는 쓰레드가 공유하는 자원에 대한 일관성이 보장되어야 한다.
즉, 특정 쓰레드에서 공유 자원의 데이터를 변경하면 다른 쓰레드에서도 똑같이 변경된 데이터를 다뤄야한다.

-> 대부분 맞긴 하지만 항상 그렇지는 않아서 공식처럼 보기엔 무리가 있습니다.
가령 C++에서 느슨한(relaxed) 메모리 모델 방식을 채택하면 당장
특정 쓰레드에서 뭔가를 수정하더라도
다른 쓰레드가 그것을 한참 후에 발견할 수도 있는데,
그게 별다른 문제가 되지 않는 상황도 더러 존재합니다.

Lock을 거는 주된 이유는 일관성보다는
동시에 공유 데이터에 접근해서 수정하는게 문제가 되기 때문입니다.
데이터 일관성만 문제인 상황이었다면 lock까지 가지 않고 volatile로도 충분합니다.

이러한 문제를 해결하기 위해 쓰레드가 공유 자원에 접근하기 전 Lock을 걸고 들어가서 다른 쓰레드가 해당 자원에 접근하지 못하도록 막고, UnLock을 통해서 다른 쓰레드가 접근할 수 있게 해준다. 이 때 접근한 쓰레드는 변경된 공유 자원 데이터를 사용하게 된다. 이렇게 이해한게 맞는건가요 ? 

-> 네! 이 부분은 맞습니다.

그런데 Lock을 통해서 원자성을 구현한다고 이해하고 있는데 이게 맞는건지 궁금합니다... 

-> 원자성에 대한 얘기는 모든 연산이 꼭 원자적으로 이루어져야 한다는 것은 아니고,
Lock 내부에 있는 모든 연산이 그래야 한다는 것은 더욱 아닙니다.
Lock은 말 그대로 신호등처럼 순차적으로 접근하기 위한 도구이지
어떤 연산이 원자적으로 이루어진다는 보장을 하는 것은 아닙니다.

반대로 어떤 연산이 원자적으로 (All or Nothing)으로 이루어진다고 한다면,
멀티쓰레드 환경에서 해당 연산이 동시에 실행되더라도 문제되지 않는다 쪽에 가깝습니다.

가령 number++이라거나 number--와 같은 단순 덧셈 연산도
실제 바이너리 코드를 까보면 3단계에 걸쳐서
- 1) 데이터를 eax 레지스터에 갖고 오고
- 2) eax 값을 1 증가시키고
- 3) eax 값을 다시 데이터에 저장

하는 형태로 이루어지기 때문에 쓰레드 사이에 경합이 일어나면 문제가 일어났던 겁니다.
(2단계를 호출하고 3은 아직 안 한 상태에서, 다른 쓰레드가 끼어들어 1을 실행한다거나..)
그래서 해결책으로 number++를 atomic하게 만드는 Interlocked을 활용했던 것이죠.

y_y님의 프로필 이미지
y_y

작성한 질문수

질문하기