C++์์ DeadLock(๊ต์ฐฉ ์ํ)์ด ๋ฐ์ํ๋ ์์ธ๊ณผ ์กฐ๊ฑด, ์ด๋ฅผ ์๋ฐฉํ๊ฑฐ๋ ํํผํ๊ธฐ ์ํ ์ค์ ์ฝ๋ ์์, ๋ฝ ์์ ํต์ผ, std::lock, adopt_lock, ๊ทธ๋ฆฌ๊ณ RAII ๊ธฐ๋ฐ ๋ฝ ๊ด๋ฆฌ ๋ฐฉ๋ฒ ์ ๋ฆฌ
DeadLock์ ๋ ์ด์์ ์ค๋ ๋๋ ํ๋ก์ธ์ค๊ฐ ์๋ก์ ์์์ ์ ์ ํ๊ณ ๊ทธ ์์์ด ํด์ ๋๊ธฐ๋ง์ ๊ธฐ๋ค๋ฆฌ๋ค๊ฐ, ๊ฒฐ๊ตญ ๋ชจ๋๊ฐ ์์ํ ๋๊ธฐ ์ํ์ ๋น ์ง๋ ํ์์ด๋ค. ์ด ์ํ์์๋ ์ด๋ค ์์ ๋ ๋ ์ด์ ์งํ๋ ์ ์๋ค.
๋ํ์ ๋น์ :
์๋ฌผ์ ๊ฐ 2๊ฐ ์๊ณ , ์ฌ์ฉ์ A๋ ์๋ฌผ์ 1์ ๊ฐ์ง๊ณ ์๋ฌผ์ 2๋ฅผ ๊ธฐ๋ค๋ฆฌ๊ณ , ์ฌ์ฉ์ B๋ ์๋ฌผ์ 2๋ฅผ ๊ฐ์ง๊ณ ์๋ฌผ์ 1์ ๊ธฐ๋ค๋ฆฌ๋ ์ํฉ.
์ด ๊ตฌ์กฐ๋ ์์ํ ํด์๋์ง ์๋๋ค โ ์ด๊ฒ์ด DeadLock.
| ์กฐ๊ฑด | ์ค๋ช |
|---|---|
| ์ํธ๋ฐฐ์ (Mutual Exclusion) | ํ๋์ ์์์ ํ ๋ฒ์ ํ ํ๋ก์ธ์ค๋ง ์ฌ์ฉํ ์ ์๋ค. |
| ์ ์ ๋๊ธฐ (Hold and Wait) | ์์์ ์ ์ ํ ์ํ์์, ๋ค๋ฅธ ์์์ ์์ฒญํ๋ฉฐ ๊ธฐ๋ค๋ฆฐ๋ค. |
| ๋น์ ์ (No Preemption) | ์ด๋ฏธ ์ ์ ์ค์ธ ์์์ ๊ฐ์ ๋ก ํ์ํ ์ ์๋ค. |
| ์ํ ๋๊ธฐ (Circular Wait) | ๋๊ธฐ ์ค์ธ ํ๋ก์ธ์ค๋ค์ด ์๋ก ์์์ ์ ์ ํ๋ฉฐ ์ํ ๊ตฌ์กฐ๋ฅผ ์ด๋ฃฌ๋ค. |
โก๏ธ ์ด ๋ค ๊ฐ์ง๊ฐ ๋ชจ๋ ๋ง์กฑ๋๋ฉด DeadLock์ด ๋ฐ์ํ ์ ์๋ค.
๋ ๊ฐ์ mutex๋ฅผ ์ฌ์ฉํ๋ Add()์ Sub() ํจ์๊ฐ ์๋ค๊ณ ํ์:
int sum = 0;
mutex mutexAdd;
mutex mutexSub;
Add() ํจ์void Add()
{
for (int i = 0; i < 1000; ++i)
{
mutexAdd.lock();
mutexSub.lock();
++sum;
mutexAdd.unlock();
mutexSub.unlock();
}
}
Sub() ํจ์void Sub()
{
for (int i = 0; i < 1000; ++i)
{
mutexSub.lock();
mutexAdd.lock();
--sum;
mutexSub.unlock();
mutexAdd.unlock();
}
}
Add()๋mutexAdd โ mutexSub์์๋ก,Sub()๋mutexSub โ mutexAdd์์๋ก ๋ฝ์ ๊ฑด๋ค.
๋ ์ค๋ ๋๊ฐ ๊ฐ์ ์ฒซ ๋ฒ์งธ ๋ฝ์ ๊ฑธ๊ณ , ์๋ก ์๋ ๋ฝ์ ๊ธฐ๋ค๋ฆฌ๋ฉด DeadLock ๋ฐ์.
// UserManager::ProcessSave
Account* account = AccountManager::Instance()->GetAccount(100); // accountLock
lock_guard<mutex> guard(_mutex); // userLock
// AccountManager::ProcessLogin
lock_guard<mutex> guard(_mutex); // accountLock
User* user = UserManager::Instance()->GetUser(100); // userLock
๋ฝ ํ๋ ์์๊ฐ ๋ค๋ฅด๋ค.
ํ๋๋ account ๋จผ์ , ๋ค๋ฅธ ํ๋๋ user ๋จผ์ โ DeadLock ๊ฐ๋ฅ.
| ์ฉ์ด | ์ค๋ช |
|---|---|
DeadLock | ์์์ ๊ธฐ๋ค๋ฆฌ๋ฉฐ ์ค๋ ๋/ํ๋ก์ธ์ค๊ฐ ๋ฉ์ถ๋ ํ์ |
mutex | ์ํธ ๋ฐฐ์ ๋ฅผ ์ํ ๊ธฐ๋ณธ ๋๊ธฐํ ๊ฐ์ฒด |
lock_guard | ์์ฑ ์ lock, ์๋ฉธ ์ unlock (RAII ๊ธฐ๋ฐ) |
std::lock | ์ฌ๋ฌ mutex๋ฅผ ๋์์ DeadLock ์์ด ์ ๊ทธ๋ ํจ์ |
adopt_lock | ์ด๋ฏธ lock๋ mutex๋ฅผ RAII ๊ฐ์ฒด์ ์์ํ๋ ํ๊ทธ |
RAII | ๊ฐ์ฒด ์๋ช ์ฃผ๊ธฐ๋ก ์์์ ์๋ ๊ด๋ฆฌํ๋ C++ ํจํด |
์ํ ๋๊ธฐ | ์์ ๋๊ธฐ๊ฐ ๊ณ ๋ฆฌ ๊ตฌ์กฐ๋ก ๋ฐ๋ณต๋๋ ์ํ |
std::lock + adopt_lockmutex m1, m2;
std::lock(m1, m2); // DeadLock ์์ด ๋์์ lock
std::unique_lock<mutex> u1(m1, adopt_lock);
std::unique_lock<mutex> u2(m2, adopt_lock);
std::lock()์ ๋ด๋ถ์ ์ผ๋ก ์์ ํ ์์๋ก ๋ฝ์ ๊ฑด๋ค.adopt_lock์ ํตํด RAII๋ก ์๋ unlock์ ์์ํ๋ค.lock_guard ๋์ unique_lock์ ์ฌ์ฉํ๋ฉด move, defer_lock ๊ฐ์ ๊ณ ๊ธ ์ ์ด๋ ๊ฐ๋ฅ.| ์ ๋ต | ์ค๋ช |
|---|---|
| ์์ ํต์ผ | ํญ์ ๊ฐ์ ์์๋ก lock์ ๊ฑธ๋๋ก ๊ฐ์ (ID๋ก ์ ๋ ฌ ๋ฑ) |
| std::lock | ๋ฝ ์์๋ฅผ ์๋ ์ ๋ ฌํ์ฌ DeadLock ๋ฐฉ์ง |
| RAII ํ์ฉ | ์์ธ ๋ฐ์์ด๋ ํ์ถ ์์๋ unlock์ด ์๋์ผ๋ก ์ํ๋จ |
| ํ์ง ์๊ณ ๋ฆฌ์ฆ | ๊ทธ๋ํ ์ํ ํ์ง๋ก DeadLock์ ๋ฏธ๋ฆฌ ๋ฐ๊ฒฌ ๊ฐ๋ฅ |
std::lock๊ณผ adopt_lock์ ์ด์ฉํ RAII ๊ตฌ์กฐscoped_lock, try_lock ๋ฑ๋ ๊ณ ๋ ค