์ˆ˜์—…


๐Ÿงต ์ฃผ์ œ

C++์—์„œ DeadLock(๊ต์ฐฉ ์ƒํƒœ)์ด ๋ฐœ์ƒํ•˜๋Š” ์›์ธ๊ณผ ์กฐ๊ฑด, ์ด๋ฅผ ์˜ˆ๋ฐฉํ•˜๊ฑฐ๋‚˜ ํšŒํ”ผํ•˜๊ธฐ ์œ„ํ•œ ์‹ค์ „ ์ฝ”๋“œ ์˜ˆ์‹œ, ๋ฝ ์ˆœ์„œ ํ†ต์ผ, std::lock, adopt_lock, ๊ทธ๋ฆฌ๊ณ  RAII ๊ธฐ๋ฐ˜ ๋ฝ ๊ด€๋ฆฌ ๋ฐฉ๋ฒ• ์ •๋ฆฌ


๐Ÿ“˜ ๊ฐœ๋…

โœ… DeadLock(๊ต์ฐฉ ์ƒํƒœ)์ด๋ž€?

DeadLock์€ ๋‘˜ ์ด์ƒ์˜ ์Šค๋ ˆ๋“œ๋‚˜ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์„œ๋กœ์˜ ์ž์›์„ ์ ์œ ํ•˜๊ณ  ๊ทธ ์ž์›์ด ํ•ด์ œ๋˜๊ธฐ๋งŒ์„ ๊ธฐ๋‹ค๋ฆฌ๋‹ค๊ฐ€, ๊ฒฐ๊ตญ ๋ชจ๋‘๊ฐ€ ์˜์›ํžˆ ๋Œ€๊ธฐ ์ƒํƒœ์— ๋น ์ง€๋Š” ํ˜„์ƒ์ด๋‹ค. ์ด ์ƒํƒœ์—์„œ๋Š” ์–ด๋–ค ์ž‘์—…๋„ ๋” ์ด์ƒ ์ง„ํ–‰๋  ์ˆ˜ ์—†๋‹ค.

๋Œ€ํ‘œ์  ๋น„์œ :

์ž๋ฌผ์‡ ๊ฐ€ 2๊ฐœ ์žˆ๊ณ , ์‚ฌ์šฉ์ž A๋Š” ์ž๋ฌผ์‡  1์„ ๊ฐ€์ง€๊ณ  ์ž๋ฌผ์‡  2๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๊ณ , ์‚ฌ์šฉ์ž B๋Š” ์ž๋ฌผ์‡  2๋ฅผ ๊ฐ€์ง€๊ณ  ์ž๋ฌผ์‡  1์„ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์ƒํ™ฉ.
์ด ๊ตฌ์กฐ๋Š” ์˜์›ํžˆ ํ•ด์†Œ๋˜์ง€ ์•Š๋Š”๋‹ค โ†’ ์ด๊ฒƒ์ด DeadLock.


โœ… DeadLock ๋ฐœ์ƒ ์กฐ๊ฑด (4๊ฐ€์ง€ ํ•„์ˆ˜ ์กฐ๊ฑด)

์กฐ๊ฑด์„ค๋ช…
์ƒํ˜ธ๋ฐฐ์ œ (Mutual Exclusion)ํ•˜๋‚˜์˜ ์ž์›์€ ํ•œ ๋ฒˆ์— ํ•œ ํ”„๋กœ์„ธ์Šค๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
์ ์œ  ๋Œ€๊ธฐ (Hold and Wait)์ž์›์„ ์ ์œ ํ•œ ์ƒํƒœ์—์„œ, ๋‹ค๋ฅธ ์ž์›์„ ์š”์ฒญํ•˜๋ฉฐ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.
๋น„์„ ์  (No Preemption)์ด๋ฏธ ์ ์œ  ์ค‘์ธ ์ž์›์„ ๊ฐ•์ œ๋กœ ํšŒ์ˆ˜ํ•  ์ˆ˜ ์—†๋‹ค.
์ˆœํ™˜ ๋Œ€๊ธฐ (Circular Wait)๋Œ€๊ธฐ ์ค‘์ธ ํ”„๋กœ์„ธ์Šค๋“ค์ด ์„œ๋กœ ์ž์›์„ ์ ์œ ํ•˜๋ฉฐ ์ˆœํ™˜ ๊ตฌ์กฐ๋ฅผ ์ด๋ฃฌ๋‹ค.

โžก๏ธ ์ด ๋„ค ๊ฐ€์ง€๊ฐ€ ๋ชจ๋‘ ๋งŒ์กฑ๋˜๋ฉด DeadLock์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.


โœ… 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 ๋ฐœ์ƒ.


โœ… ์‹ค๋ฌด ์˜ˆ์‹œ: AccountManager์™€ UserManager ๊ฐ„ 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++ ํŒจํ„ด
์ˆœํ™˜ ๋Œ€๊ธฐ์ž์› ๋Œ€๊ธฐ๊ฐ€ ๊ณ ๋ฆฌ ๊ตฌ์กฐ๋กœ ๋ฐ˜๋ณต๋˜๋Š” ์ƒํƒœ

๐Ÿ’ป ์ฝ”๋“œ ๋ถ„์„

โœ… DeadLock ํšŒํ”ผ: std::lock + adopt_lock

mutex 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 ๊ฐ™์€ ๊ณ ๊ธ‰ ์ œ์–ด๋„ ๊ฐ€๋Šฅ.

โœ… DeadLock ํšŒํ”ผ ์ „๋žต ์š”์•ฝ

์ „๋žต์„ค๋ช…
์ˆœ์„œ ํ†ต์ผํ•ญ์ƒ ๊ฐ™์€ ์ˆœ์„œ๋กœ lock์„ ๊ฑธ๋„๋ก ๊ฐ•์ œ (ID๋กœ ์ •๋ ฌ ๋“ฑ)
std::lock๋ฝ ์ˆœ์„œ๋ฅผ ์ž๋™ ์ •๋ ฌํ•˜์—ฌ DeadLock ๋ฐฉ์ง€
RAII ํ™œ์šฉ์˜ˆ์™ธ ๋ฐœ์ƒ์ด๋‚˜ ํƒˆ์ถœ ์‹œ์—๋„ unlock์ด ์ž๋™์œผ๋กœ ์ˆ˜ํ–‰๋จ
ํƒ์ง€ ์•Œ๊ณ ๋ฆฌ์ฆ˜๊ทธ๋ž˜ํ”„ ์ˆœํ™˜ ํƒ์ง€๋กœ DeadLock์„ ๋ฏธ๋ฆฌ ๋ฐœ๊ฒฌ ๊ฐ€๋Šฅ

๐Ÿ“ท ์‹œ๊ฐํ™” ์ด๋ฏธ์ง€ ์„ค๋ช…

  • ์ฒซ ๋ฒˆ์งธ ์ด๋ฏธ์ง€: ๋‘ ์‚ฌ์šฉ์ž๊ฐ€ ๊ฐ๊ฐ ์ž๋ฌผ์‡ ๋ฅผ ์žก๊ณ  ์ƒ๋Œ€ ์ž๋ฌผ์‡ ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๊ตฌ์กฐ โ†’ DeadLock ์‹œ๊ฐ์  ํ‘œํ˜„.
  • ๋‘ ๋ฒˆ์งธ ์ด๋ฏธ์ง€: ํ”„๋กœ์„ธ์Šค ๊ฐ„ ์ž์› ์š”์ฒญ์ด ์ˆœํ™˜ ํ˜•ํƒœ๋กœ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋Š” Directed Graph โ†’ ์ˆœํ™˜ ๋Œ€๊ธฐ ์กฐ๊ฑด ์„ค๋ช…์šฉ.

๐ŸŽฏ ํ•ต์‹ฌ

  • DeadLock์€ 4๊ฐ€์ง€ ์กฐ๊ฑด(์ƒํ˜ธ๋ฐฐ์ œ, ์ ์œ ๋Œ€๊ธฐ, ๋น„์„ ์ , ์ˆœํ™˜๋Œ€๊ธฐ)์ด ๋™์‹œ์— ๋งŒ์กฑ๋  ๋•Œ ๋ฐœ์ƒํ•œ๋‹ค.
  • ๋ฝ์„ ๊ฑฐ๋Š” ์ˆœ์„œ๊ฐ€ ์ผ๊ด€๋˜์ง€ ์•Š๊ฑฐ๋‚˜, ๋ฝ ํ•ด์ œ๊ฐ€ ๋ˆ„๋ฝ๋˜๋ฉด DeadLock์ด ๋ฐœ์ƒํ•œ๋‹ค.
  • ๋ฐฉ์ง€ ์ „๋žต์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค:
    • ํ•ญ์ƒ ๋ฝ ํš๋“ ์ˆœ์„œ ํ†ต์ผ
    • std::lock๊ณผ adopt_lock์„ ์ด์šฉํ•œ RAII ๊ตฌ์กฐ
    • ๊ฐ€๋Šฅํ•˜๋‹ค๋ฉด scoped_lock, try_lock ๋“ฑ๋„ ๊ณ ๋ ค
  • DeadLock์€ ๋ฐœ์ƒ ์ดํ›„ ๋ณต๊ตฌ๋ณด๋‹ค, ์‚ฌ์ „ ์˜ˆ๋ฐฉ์ด ํ›จ์”ฌ ์ค‘์š”ํ•˜๋‹ค.

profile
๏งกๅฎถ๋„ค_๊ณต๋ถ€๋ฐฉ

0๊ฐœ์˜ ๋Œ“๊ธ€