// <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 |