[C++]Lock 기초

강병우·2023년 7월 10일
0

멀티스레드

목록 보기
3/3

2023-06-30에 작성된 소스코드입니다.

Lock

여러 개의 스레드가 하나의 벡터에 원소를 집어넣을 경우 에러가 발생한다. 벡터의 크기가 원소의 개수보다 많을 경우 새 메모리를 할당하고 데이터를 다시 쓰게 되는데 이 과정에서 2개 이상의 스레드가 동시에 메모리를 지우면서 에러가 발생한다.

Atomic은 안되나?

이전에 배운 atomic의 경우, 데이터를 쓰고 불러오는, 즉 loadstore만 사용할 수 있기 때문에 vector와 같은 STL을 사용할 수 없다.

Atomic 대신 Lock을 쓰자.

그래서 2개 이상의 스레드가 하나의 메모리를 참조할 때, Lock을 걸어 한 스레드가 메모리를 참조하고 있음을 알려줌으로써 다른 스레드가 참조하지 못 하게 할 수 있다. mutex를 통해 Lock을 걸 수 있다.

#include "pch.h"
#include <iostream>
#include "CorePch.h"
#include <thread>
#include <atomic>
#include <mutex>

vector<int32> v;

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

// RAII (Resource Acquisition Is Initialization)
template<typename T>
class LockGuard
{
public:
	LockGuard(T& m)
	{
		_mutex = &m;
		_mutex->lock();
	}
	~LockGuard()
	{
		_mutex->unlock();
	}

private:
	T* _mutex;
};

void Push()
{
	for (int32 i = 0; i < 10000; i++)
	{
		// 자물쇠 잠근다. 다른 사람들이 못 쓰게!
		// 자동문임. 생성자에서 락을 건 뒤, 실행이 끝나면 자동으로 소멸되면서 잠금 해제
		LockGuard<mutex> lockguard(m);
		//lock_guard<mutex> lockGuard(m);	// 위와 같음
		//unique_lock<mutex> uniqueLock(m, defer_lock);	// 잠금 시점을 조정할 수 있음. 그 외엔 똑같음.
		//uniqueLock.lock();
		//m.lock();

		v.push_back(i);

		// 자물쇠를 푼다. 이제 다른 사람들도 사용할 수 있다.
		//m.unlock();
	}
		
}

int main()
{
	v.reserve(20000);

	thread t1(Push);
	thread t2(Push);

	t1.join();
	t2.join();

	cout << v.size() << endl;

}
  • LockGuard : 직접 구현한 클래스이며, 생성자 호출과 함께 Lock을 걸며, 소멸하면 해제된다. 즉, 선언과 동시에 락을 걸고 생명주기가 끝나면 자동으로 락이 풀린다.
  • void Push : 벡터에 원소를 추가하는 함수이며, 추가할 때마다 LockGuard를 통해 메모리 참조를 제어한다.

참조 : [C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part4: 게임 서버

0개의 댓글

관련 채용 정보