// <AccountManager.h>============================================================= =
#include <mutex>

class Account
{
	// TODO
};
class AccountManager
{
public:
	static AccountManager* Instance()
	{
		static AccountManager interface;
		return &interface;
	}

	Account* GetAccount(int _id)
	{
		lock_guard<mutex> guard(_mutex);
		return nullptr;
	}
    
	void ProcessLogin()
	{
		lock_guard<mutex> guard(_mutex); //accountLock
		UserManager::instance()->GetUser(100); // GetUser() 함수에도 락가드가 있음
	}

private:
	mutex _mutex;
    
};

// < UserManager.h>=================================================================
#include <mutex>

class User
{
};

class UserManager
{
public:
	static UserManager* instance()
	{
		static UserManager instnace;
		return &instnace;
	}
    
	User* GetUser(int32 _id)
	{
		lock_guard<mutex> guard(_mutex);
		return nullptr;
	}
    
	void ProcessSave()
	{
		lock_guard<mutex> guard(_mutex); //userLock
		AccountManager::Instance()->GetAccount(100); // GetAccount() 함수에도 락가드가 있음
	}
    
private:
	mutex _mutex;
    
};

// < main.cpp>=====================================================================
#include <iostream>
#include <thread>
#include <atomic>
#include <mutex>
#include "AccountManager.h"
#include "UserManager.h"

void Func()
{
	for (int32 i = 0; i < 100; i++)
	{
		UserManager::instance()->ProcessSave();
	}
}

void Func2()
{
	for (int32 i = 0; i < 100; i++)
	{
		AccountManager::Instance()->ProcessLogin();
	}
}

int main()
{
	std::thread t1(Func);
	std::thread t2(Func2);
	t1.join();
	t2.join();
	cout << "Jobs Done" << endl;
}

 

해당 코드는 실행이 안될 때가 많은데, 이유는 데드락이 발생하기 때문입니다.

 

1. 두 스레드가 각각 Func(), Func2()에 대한 작업을 실행

2. 각 함수는 ProcessSave(), ProcessLogin()을 실행

3. 이들은 자신이 속한 클래스의 mutex 자원을 활용

4. 여기서 다음의 상황이 발생하는 것

    4-1. t1이  ProcessSave()로 진입하며 UserManager의 mutex 자원 획득 후 AccountManager의 GetUser()로 넘어감

    4-2. t2가 ProcessLogin()으로 진입하며 AccountManager의 mutex 자원 획득 후 UserManager의 GetAccount()로 넘어감

    4-3. 여기서 t1은 t2가 가져간 AccountManager의 mutex 자원이 반환되기를 기다림

    4-4. 다음으로 t2는 t1이 가져간 UserManager의 mutex 자원이 반환되기를 기다림

 

위의 상황에서, 4번이 계속 반복되는 경우 데드락이 발생했다고 볼 수 있습니다(ABBA 데드락). 이 패턴은 아래와 같이 락 순서를 통일하면 해결되기는 합니다.

void AccountManager::ProcessLogin()
{
	lock_guard<mutex> guard(_mutex); //accountLock
	UserManager::instance()->GetUser(100); // GetUser() 함수에도 락가드가 있음
}

void UserManager::ProcessSave()
{
	AccountManager::Instance()->GetAccount(100); // GetAccount() 함수에도 락가드가 있음
	lock_guard<mutex> guard(_mutex); //userLock
}

 

하지만 데드락은 이런 경우에서만 발생하는 것이 아니라, 다양한 패턴에서 발생하기 때문에 작업에 주의를 기울여야 합니다.

'서버' 카테고리의 다른 글

[Server] 스핀락(Spinlock)과 sleep  (0) 2025.11.14
[Server] Lock(mutex)  (0) 2025.03.17
[Server] atomic  (0) 2025.03.17
[Server] 스레드  (0) 2025.03.17

+ Recent posts