프린스 알리 2025. 1. 16. 21:28

내일배움캠프 Node.js 트랙 56일차

스레드

뮤텍스

뮤텍스는 상호 배제(MUTual EXclusion)의 줄임말이며, 스레드 간의 경쟁상태를 해소하기 위해 사용된다.

스레드와 경쟁 상태

스레드 간의 경쟁 상태를 이해하기 위해선 스레드가 실제 어떻게 실행되는지를 이해해야 한다. 우리가 알아야 하는 건 컴퓨터는 생각보다 똑똑하지 않다는 점이다. 그야 물론 똑똑하기야 하다만, 인간에 비할 수는 없단 얘기다.
스레드에게 두 가지 일을 시킨다고 생각해보자. 보통 사람에게 두 가지 일을 해달라고 부탁한다면 하나를 먼저 하고 그 다음 나머지 일을 처리할 것이다. 그러나 컴퓨터 운영체제는 일을 번갈아 수행한다. 1번 스레드를 실행하다가 2번 스레드를 실행하고 또 1번을 실행하고 3번을 실행하는 등 왔다갔다 프로세스를 진행한다.
이런 과정을 컨텍스트 스위치라고 한다.

우스운 건 이 컨텍스트 스위치가 컴퓨터 입장에서도 부담스러운 일이라는 점이다. 컴퓨터는 말했다시피 멍청해서 하던 일을 멈추면 금방 잊어버린다. 따라서 1번 스레드가 하던 일들을 저장하고, 2번 스레드로 전환했다가 다시 저장한 걸 복원한 다음 1번 일을 실행하는 것이다. 당연히 이런 방식엔 연산이 많이 필요할 테고, 스위치를 하는 데 걸리는 시간도 있을 테니 비효율적이라고 할 수 있다. 게다가 컨텍스트 스위치는 무작위로 발생하기에 연산을 두 번 하거나 값을 건너뛰고 연산하는 등 여러 가지 문제를 발생시킨다.

이럴 때 원자성과 일관성을 유지하기 위해 필요한 조치를 동기화라고 부른다. 그리고 그 대표적인 방식이 뮤텍스(임계 영역) 잠금 기법이다.

뮤텍스(임계 영역)

뮤텍스(임계 영역)를 쉽게 설명하자면 화장실로 비유할 수 있다. 화장실을 먼저 선점한 스레드가 볼일을 다 마치기 전까지 다른 스레드들은 그 칸을 이용할 수 없다. 이걸 코드로는 lock(), unlock() 함수를 이용해서 구현하게 된다.

그런데 잠금 기법에는 심각한 문제가 있다. 그게 바로 아래 설명할 데드락이다.

교착 상태(데드락)

멀티스레드 프로그래밍에서 교착 상태란 두 스레드가 서로를 기다리는 상황을 의미한다. 스레드 1이 스레드 2가 하던 일이 끝날 때까지 기다리는데, 사실 스레드2도 스레드1이 하던 일이 끝날 때까지 기다리는 상황이다. 어디서 많이 들어본 이야기다. 아, 이건 DB에서도 일어나는 일이었다. 우리가 왜 트랜젝션을 사용하게 되었는지 돌이켜보면 스레드에서의 데드락 또한 쉽게 이해가 간다.

교착 상태를 예방하려면

데드락을 피하기 위해선 여러 뮤텍스의 잠금 순서를 먼저 그래프로 그려두어야 한다. 예를 들어 뮤텍스 A, 뮤텍스B, 뮤텍스C가 있을 때 A, B, C 순서대로 잠금 기회를 얻는 것이다. 여기서 오해하지 않아야 하는 건 중간에 건너 뛰거나 하나쯤 빼먹어도 순서만 지키면 상관 없다는 점이다. 거꾸로 잠그지만 않으면 된다!