본문 바로가기

Programming/CPP11&14

[C++11] std::mutex를 통한 thread 동기화

반응형

2015/06/28 - [Programming/C++11&14] - [C++11] thread 지원 - future를 통한 return값 획득 (2)

이미 대부분의 OS는 동기화를 위한 다양한 장치가 마련되어 있습니다.

thread가 C++11에서 직접 지원하면서 동기화를 위한 std::mutex가 추가되었습니다.

헤더는 <mutex>이며 사용 방법은 다음과 같습니다.

#include <thread>
#include <mutex>
#include <iostream>

std::mutex mtx;
void ThreadFunc(int nID, int& nVal)
{
	for (int i = 0 ; i < 5 ; ++i)
	{
		mtx.lock();

		std::cout << "Value of " << nID << " -> " << nVal << std::endl;
		++nVal;

		mtx.unlock();
	}
}

int main()
{
	int nVal = 0;
	std::thread th1(ThreadFunc, 0, std::ref(nVal));
	std::thread th2(ThreadFunc, 1, std::ref(nVal));

	th1.join();
	th2.join();

	return 0;
}

간단하게 객체를 생성하고 lock()으로 권한을 획득하고 공유 데이터에 접근합니다.

그리고 다 사용한 이후에 unlock()을 통해서 해제하면 됩니다.

lock()과 unlock()을 지우면 화면에 정상적으로 출력되지 않는 것을 확인할 수 있습니다.

다만 가끔씩 정상적인 것처럼 출력이 될 수도 있습니다.

그리고 try_lock() 메소드는 권한을 획득하기 위해서 시도합니다.

결과가 바로 리턴되며, 획득에 성공할 경우 true, 실패할 경우 false를 리턴합니다.

바로 획득이 가능할 경우만 작업을 처리하고 싶을 경우에 사용하면 됩니다.

lock()과 try_lock()은 이미 권한을 획득한 thread에서 호출할 경우 미정의 동작이 발생합니다.

lock()을 연달아 사용하고 싶을 때는 std::recursive_mutex를 사용하면 됩니다.

이 경우에는 lock()을 호출한 회수와 동일하게 unlock()을 호출해야 합니다.

#include <thread>
#include <mutex>
#include <iostream>

std::recursive_mutex mtx;
void ThreadFunc(int nID, int& nVal)
{
	for (int i = 0; i < 5; ++i)
	{
		std::lock_guard<std::recursive_mutex> lg(mtx);

		std::cout << "Value of " << nID << " -> " << nVal << std::endl;
		++nVal;
	}
}

int main()
{
	int nVal = 0;
	std::thread th1(ThreadFunc, 0, std::ref(nVal));
	std::thread th2(ThreadFunc, 1, std::ref(nVal));

	th1.join();
	th2.join();

	return 0;
}

std::lock_guard는 RAII(Resource Acquisition Is Initialization) 방식으로 동작합니다.

초기화할 때 lock을 획득하고 unlock()을 호출하지 않아도 범위를 벗어나면 자동적으로 해제됩니다.

lock_guard의 기능에 mutex의 메소드까지 호출 가능한 std::unique_lock도 존재합니다.

recursive_mutex를 사용하는 이유는 동일한 mutex를 사용하는 함수가 다른 함수를 호출할 수 있기 때문입니다.

또한 std::timed_mutex와 std::recursive_timed_mutex 등이 존재합니다.

try_lock_until()과 try_lock_for() 등이 추가로 제공됩니다.

이 메소드들은 바로 결과를 주지 않고 지정된 시간만큼 재시도를 하다가 결과를 리턴합니다.

또한 C++17에서는 std::shared_mutex도 추가될 예정입니다.

반응형