Mutex

나무에물주기·2023년 5월 22일
1
post-thumbnail

Mutex란 무엇인가?

Mutex는 'Mutual Exclusion'의 약어로서, 한글로는 '상호 배제'라는 의미를 가지고 있다. 그 이름에서 알 수 있듯이, Mutex는 여러 개의 스레드가 공유 데이터에 동시에 접근하는 것을 제한하는 역할을 수행하는 도구다. 멀티스레드 환경에서 스레드들이 공유 데이터를 안전하게 처리할 수 있도록 지원하는 것이 그 목표다.

Mutex의 중요성

멀티스레드 프로그래밍에서는 여러 스레드가 동시에 동일한 데이터에 접근하는 경우 문제가 발생할 수 있다. 이를 경쟁 상태(Race Condition)라고 부르며, 데이터가 예기치 않게 변경되어 프로그램의 결과를 예측하기 어렵게 만드는 원인이 된다. 이런 상황을 방지하기 위해 Mutex와 같은 동기화 도구를 사용한다.

스레드는 공유 데이터에 접근하기 전에 Mutex를 잠그고(lock), 사용 후에 Mutex를 해제(unlock)한다. Mutex가 잠겨 있으면 다른 스레드는 해당 Mutex가 해제될 때까지 대기해야 한다. 이를 통해 한 번에 한 스레드만이 공유 데이터에 접근할 수 있도록 제한하고, 데이터의 일관성을 보장한다.

Mutex와 RAII

Mutex 객체는 보통 lock과 unlock 메서드를 제공한다. 이 두 메서드는 함께 사용되어야 한다. lock 메서드는 해당 Mutex가 이미 잠겨있지 않다면 잠그고, 잠겨 있다면 잠금이 해제될 때까지 대기한다. 반면에 unlock 메서드는 Mutex를 잠그는 것을 해제한다.

Mutex를 사용하면서 lock과 unlock 사이에서 예외가 발생하거나 논리적인 오류로 인해 unlock이 누락되는 등의 상황을 방지하기 위해 RAII(Resource Acquisition Is Initialization) 기법이 활용된다. 이는 리소스를 할당하는 것과 동시에 그 리소스의 소유권을 관리하는 객체를 생성하는 원칙이다.

예제 코드 설명

아래 예제에서는 Mutex를 활용하여 멀티스레드 환경에서 공유 데이터인 벡터 v를 안전하게 관리하는 방법을 보여준다. 두 개의 스레드(t1, t2)가 동시에 벡터에 값을 추가하는 Push 함수를 실행한다.이 때 벡터에 값이 추가되는 동안 다른 스레드가 벡터에 접근하는 것을 막기 위해 mutex m을 사용하고 있다.

// Push 함수 : Lock을 걸고, 벡터에 값을 추가하는 함수
void Push()
{
	for (int32 i = 0; i < 10000; i++)
	{
		std::lock_guard<std::mutex> LockGuard(m);
		v.push_back(i);
		if (i == 5000)
		{
			break;
		}
	}
}

이때, std::lock_guard<std::mutex>를 사용하여 lock과 unlock을 자동으로 관리한다. 이는 RAII 기법을 활용한 것으로, LockGuard 객체가 생성될 때 mutex를 잠그고, 소멸될 때 이를 해제한다. 따라서 예외 상황에 대비할 수 있으며, 코드의 가독성도 향상시킬 수 있다.

Mutex의 구현 방식과 주의 사항

Mutex의 구현 방식은 OS나 프로그래밍 언어, 라이브러리 등에 따라 다르다. 대부분의 경우, Mutex는 OS의 핵심 기능을 사용하여 구현된다. 예를 들어, Linux에서는 futex, Windows에서는 Critical Section 등을 사용한다.

Mutex를 사용할 때 주의해야 할 사항이 있다. 먼저, Mutex는 오버헤드를 발생시킬 수 있다. 따라서 공유 데이터에 접근하는 데 시간이 많이 걸리지 않는 경우, 락을 걸어서 발생하는 오버헤드가 실제 작업 시간보다 클 수 있다. 이런 상황에서는 다른 동기화 기법을 고려할 수 있다. 또한, Mutex를 잘못 사용하면 교착 상태(Deadlock)와 같은 문제가 발생할 수 있다. 예를 들어, 두 스레드가 각각 다른 Mutex를 잠그고, 서로의 Mutex를 기다리는 상황이 발생할 수 있다.

profile
개인 공부를 정리함니다

0개의 댓글