<mutex>

Yongs12 ㅣ 2024. 2. 22. 09:54

std::mutex (Mutual Exclusion)

여러 쓰레드가 동시에 공유 자원에 접근할 때 발생 할 수 있는 문제를 방지하는 역할을 해준다.

 


mutex 사용법

// Mutual Exclusive (상호배타적)
mutex m;

void Push()
{
	for (int32 i = 0; i < 10000; ++i)
	{
		// 잠금 장치
		m.lock();

		vec.push_back(i);

		// 잠금 해제
		m.unlock();
	}
}

int main()
{
	std::thread t1(Push);
	std::thread t2(Push);

	if (t1.joinable() && t2.joinable())
	{
		t1.join();
		t2.join();
	}

	cout << vec.size() << endl;
}

 

t1, t2의 두개의 쓰레드가 Push()를 실행할 때 mutex를 통해 하나의 쓰레드만 접근할 수 있도록 lock()을 통해 접근을 막고 연산이 끝나면 unlock()으로 잠금 장치를 해제한다.

 


예외 상황

// Mutual Exclusive (상호배타적)
mutex m;

void Push()
{
	for (int32 i = 0; i < 10000; ++i)
	{
		// 잠금 장치
		m.lock();

		vec.push_back(i);

		// 조건으로 인해 탈출할 경우 문제가 발생
		if (i == 5000)
		{
			break;
		}

		// 잠금 해제
		m.unlock();
	}
}

int main()
{
	std::thread t1(Push);
	std::thread t2(Push);

	if (t1.joinable() && t2.joinable())
	{
		t1.join();
		t2.join();
	}

	cout << vec.size() << endl;
}

 

조건으로 인해 break가 걸리게 되면 mutex로 잠금을 했지만 해제를 하지 않아 문제가 발생한다.

 

 

해결 방법

RAII 패턴 사용

// Mutual Exclusive (상호배타적)
mutex m;

template<typename T>
class LockGuard
{
public:
    // 생성자에서 lock을 걸고
	LockGuard(T& m)
	{
		_mutex = &m;
		_mutex->lock();
	}

    // 소멸자에서 unlock으로 해제 한다.
	~LockGuard()
	{
		_mutex->unlock();
	}

private:
	T* _mutex;
};

void Push()
{
	for (int32 i = 0; i < 10000; ++i)
	{
		// 잠금 후 범위 벗어나면 자동 해제 (RAII 패턴)
		LockGuard<mutex> lockGuard(m);

		vec.push_back(i);
	}
}

int main()
{
	std::thread t1(Push);
	std::thread t2(Push);

	if (t1.joinable() && t2.joinable())
	{
		t1.join();
		t2.join();
	}

	cout << vec.size() << endl;
}

 

 

c++ 표준이 지원하는 방법들

lock_guard, unique_lock

void Push()
{
	for (int32 i = 0; i < 10000; ++i)
	{
		// 잠금 후 범위 벗어나면 자동 해제 (RAII 패턴)
		lock_guard<mutex> lockGuard(m);

		// 기본적으로 lock_guard와 같이 RAII 패턴 적용
		// lock_guard 기능 + Lock 시점을 정할 수 있다.
		unique_lock<mutex> uniqueLock(m, defer_lock);

		uniqueLock.lock();

		vec.push_back(i);
	}
}

 

 

timed_lock

mutex m;
timed_mutex tMtx;

// 특정 시간동안 잠금을 시도한다.
if (tMtx.try_lock_for(chrono::seconds(5))) 
{
	// 잠금이 성공 되면 실행될 코드
}


// 특정 시간동안 잠금을 시도한다.
unique_lock<mutex> timeLock(m, chrono::seconds(5));

 

 

'C, C++' 카테고리의 다른 글

[[noreturn]]  (0) 2025.01.27
[[deprecated]]  (0) 2025.01.26
<atomic>  (0) 2024.02.21
<thread>  (0) 2024.02.20
weak_ptr  (0) 2023.07.17