프로그래밍-기본기/C++

(쓰레드) Mutex

독학백수 2023. 9. 8. 11:38
반응형

공유된 자원에 여러 개의 프로세스가 동시에 접근하는 현상을 막고자 전 시간엔, Atomic을 배웠다.
하지만 Atomic의 단점을 복습해보자면 연산이 느리고, 어디에서든 사용해선 안된다고 하였다.

그 어디에서든이 어떤 상황인지 C++ 코드를 통해 알아보자.

atomic<vector<int>>av;

void Push() {
	for (int32 i = 0; i < 10'000; i++)
	{
		av.push_back(i)
	}
}

가령 STL vector를 사용한다고 했을 때, 해당 STL은 모두 싱글 쓰레드 기준으로 만들어진 라이브러리다 보니
에러가 발생한다. 이 해당 에러에 대해선 바로 다음에 설명하겠고, 여하튼 atomic을 사용해서 vector의 push_back을
사용하고 싶지만, 위 코드에서는 문법 에러가 날 것이다.

즉 Atomic에서 지원하지 않는 코드가 될 수 있다.

곧바로, STL은 싱글 쓰레드 기준으로 만들어졌다고 언급하였는데, 간단히 vector의 원리를 이해해보면 조금 이해하기 쉽다
vector의 경우 reserve를 따로 하지 않고 위 코드 처럼, push_back을 통해 Capacity를 늘리게 되고 

이 때, 기존에 할당 된 Memory에서 더 큰 Memory를 할당 후 이사하게 되는데 이 과정에서 아래와 같은 현상이 일어나
크래쉬가 나타난다.

먼저 1번 쓰레드가 Vector에 접근하여 capacity가 부족해서 이사할 곳으로 이사 후 기존 vector의 메모리를 삭제하게 된다.

그 와중에 삭제된 곳에 Thread2 가 접근하니 크래쉬가 난다고 볼 수 있다.
물론 vector의 reverse함수로 미리 큰 메모리를 할당 시켜주면 크래쉬는 나지 않겠지만, 멀티 쓰레드의 공유 자원 접근 시 일어날 수 있는 문제에 대해서는 저번 시간에 언급 하였 듯, 데이터가 정상적으로 들어가지 않는 문제가 발생한다.

이를 해결하기 위해서 Mutex ( Mutal Exclution 상호 배제 ) 기법을 사용할 수 있다.

원리는 되게 간단하다. 1번 쓰레드가 일이 끝날 때 까지 다른 쓰레드가 접근 하는 것을 lock을 통해 막아두고
자기 일이 끝나면 unlock을 통해 다른 쓰레드가 접근 할 수 있도록 허용한다.

이 때, 다른 쓰레드는 lock이 걸려 있다면, 대기하다가 unlock이 되면 일을 진행한다.
사용법은 정말 간단하다.

mutex m;
void push() {
	for (int32 i = 0; i < 10'000; i++)
	{
		m.lock();
		v.push_back(i);
		m.unlock();
	}
}

위 코드와 같이 임계 영역 ( Critical Section)을 정해두고 공유 자원에 접근하는 쓰레드들이 서로 겹치지 않게
각각 단독으로 실행할 수 있도록 한다.

반응형