10 min read

OSTEP 32 Concurrency Bugs

Table of Contents

๋ณ‘ํ–‰์„ฑ ๋ฒ„๊ทธ๋Š” ๋ช‡ ๊ฐœ์˜ ์ „ํ˜•์ ์ธ ํŒจํ„ด์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ์–ด๋–ค ๊ฒฝ์šฐ๋ฅผ ํ”ผํ•ด์•ผ ์˜ฌ๋ฐ”๋ฅธ ๋ณ‘ํ–‰ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์•Œ์•„๋ณด์ž

1. ์˜ค๋ฅ˜์˜ ์ข…๋ฅ˜

ํ˜„๋Œ€ ์‘์šฉ ํ”„๋กœ๊ทธ๋žจ์—๋Š” ์–ด๋–ค ๋ณ‘ํ–‰์„ฑ ์˜ค๋ฅ˜๊ฐ€ ์žˆ์„๊นŒ? ๋‹ค์Œ์€ Lu์˜ ์—ฐ๊ตฌ ๊ฒฐ๊ณผ์ด๋‹ค.

OSTEP 32 Concurrency Bugs-1695629446329.jpeg

์ด๋Ÿฐ ์ข…๋ฅ˜์˜ ์˜ค๋ฅ˜ (๋น„ ๊ต์ฐฉ ์ƒํƒœ์™€ ๊ต์ฐฉ ์ƒํƒœ) ๋“ค์— ๋Œ€ํ•ด ์ข€ ๋” ์ž์„ธํžˆ ์•Œ์•„๋ณด์ž.

2. ๋น„ ๊ต์ฐฉ ์ƒํƒœ ์˜ค๋ฅ˜

Lu์˜ ์—ฐ๊ตฌ ๊ฒฐ๊ณผ์— ๋”ฐ๋ฅด๋ฉด, ๋น„ ๊ต์ฐฉ ์ƒํƒœ ์˜ค๋ฅ˜๊ฐ€ ๋ณ‘ํ–‰์„ฑ ๊ด€๋ จ ์˜ค๋ฅ˜์˜ ๊ณผ๋ฐ˜์ˆ˜๋ฅผ ์ฐจ์ง€ํ•œ๋‹ค. ๋น„ ๊ต์ฐฉ ์ƒํƒœ ์˜ค๋ฅ˜์˜ ๋ถ„๋ฅ˜ ์ค‘ ๋Œ€ํ‘œ์ ์ธ ์›์ž์„ฑ ์œ„๋ฐ˜ ์˜ค๋ฅ˜์™€ ์ˆœ์„œ ์œ„๋ฐ˜ ์˜ค๋ฅ˜๋ฅผ ์‚ดํŽด๋ณด์ž.

์›์ž์„ฑ ์œ„๋ฐ˜ ์˜ค๋ฅ˜ (atomicity violation)

์ฒซ ๋ฒˆ์งธ๋กœ ๋งŒ๋‚˜๊ฒŒ ๋˜๋Š” ๋ฌธ์ œ๋Š” ์›์ž์„ฑ ์œ„๋ฐ˜ ์˜ค๋ฅ˜์ด๋‹ค.

// Thread 1::
if (thdโˆ’>proc_info) {
	. . .
	fputs(thdโˆ’>proc_info, . . . ) ;
	. . .
}

// Thread 2::
thdโˆ’>proc_info = NULL;

์ด ์˜ˆ์ œ์—์„œ thd ์ž๋ฃŒ ๊ตฌ์กฐ์˜ proc_info ํ•„๋“œ๋ฅผ ๋‘ ๊ฐœ์˜ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ ‘๊ทผํ•œ๋‹ค. ์ฒซ ๋ฒˆ์งธ ์“ฐ๋ ˆ๋“œ๋Š” ๊ทธ ๊ฐ’์ด NULL์ธ์ง€ ๊ฒ€์‚ฌํ•˜๊ณ  ๊ฐ’์„ ์ถœ๋ ฅํ•œ๋‹ค. ๋‘ ๋ฒˆ์งธ ์“ฐ๋ ˆ๋“œ๋Š” ๊ฐ’์„ NULL์œผ๋กœ ์„ค์ •ํ•œ๋‹ค.

์ฒซ ๋ฒˆ์งธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๊ฒ€์‚ฌ๋ฅผ ์™„๋ฃŒํ•œ ํ›„, fputs()๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์ง์ „์— ์ธํ„ฐ๋ŸฝํŠธ๋กœ ์ธํ•ด ๋‘ ๋ฒˆ์งธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์‹คํ–‰๋˜์–ด ๊ฐ’์ด NULL๋กœ ์„ค์ •๋  ์ˆ˜ ์žˆ๋‹ค. ๋•Œ๋ฌธ์— fputs() ํ•จ์ˆ˜๋Š” NULL ํฌ์ธํ„ฐ ์—ญ์ฐธ์กฐ๋ฅผ ํ•˜๊ฒŒ ๋˜์–ด ํ”„๋กœ๊ทธ๋žจ์€ ํฌ๋ž˜์‹œ๋  ๊ฒƒ์ด๋‹ค.

๋‹ค์ˆ˜์˜ ๋ฉ”๋ชจ๋ฆฌ ์ฐธ์กฐ ์—ฐ์‚ฐ๋“ค ๊ฐ„์— ์žˆ์–ด ์˜ˆ์ƒํ–ˆ๋˜ ์ง๋ ฌ์„ฑ(serializability)์ด ๋ณด์žฅ๋˜์ง€ ์•Š์•˜๋‹ค. ์ฆ‰ ์ฝ”๋“œ์˜ ์ผ๋ถ€์— ์›์ž์„ฑ์ด ์š”๊ตฌ๋˜์—ˆ์œผ๋‚˜, ์‹คํ–‰ ์‹œ์— ๊ทธ ์›์ž์„ฑ์ด ์œ„๋ฐ˜๋˜์—ˆ๋‹ค.

ํ˜„์žฌ ์˜ˆ์ œ ์ฝ”๋“œ๋Š” proc_info ํ•„๋“œ์˜ NULL ๊ฐ’ ๊ฒ€์‚ฌ์™€ fputs() ํ˜ธ์ถœ ์‹œ proc_info๋ฅผ ์ธ์ž๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋™์ž‘์ด ์›์ž์ ์œผ๋กœ ์‹คํ–‰๋˜๋Š” ๊ฒƒ (atomicity assumption)์„ ๊ฐ€์ •ํ–ˆ๋‹ค. ์ด ๊ฐ€์ •์ด ๊นจ์ง€๋ฉด, ์ฝ”๋“œ๋Š” ์˜๋„ํ•œ ๋Œ€๋กœ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š”๋‹ค.

์ฝ”๋“œ๋ฅผ ์–ด๋–ป๊ฒŒ ์ˆ˜์ •ํ•˜๋ฉด ์ž‘๋™ํ• ๊นŒ? ๋ฝ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์–ด๋А ์“ฐ๋ ˆ๋“œ๋“  proc_info ํ•„๋“œ ์ ‘๊ทผ ์‹œ proc_info_lock ์ด๋ผ๋Š” ๋ฝ ๋ณ€์ˆ˜๋ฅผ ํš๋“ํ•˜๋„๋ก ํ•œ๋‹ค. ์ด ์ž๋ฃŒ ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋‹ค๋ฅธ ๋ชจ๋“  ์ฝ”๋“œ๋“ค๋„ ๋ฝ์œผ๋กœ ๋ณดํ˜ธํ•ด์•ผ ํ•œ๋‹ค.

pthread_mutex_t proc_info_lock = PTHREAD_MUTEX_INITIALIZER;

// Thread 1::
pthread_mutex_lock(&proc_info_lock);
if (thdโˆ’>proc_info) {
	. . .
	fputs(thdโˆ’>proc_info, . . . ) ;
	. . .
}
pthread_mutex_unlock(&proc_info_lock);

// Thread 2::
pthread_mutex_lock(&proc_info_lock);
thdโˆ’>proc_info = NULL;
pthread_mutex_unlock(&proc_info_lock);

์ˆœ์„œ ์œ„๋ฐ˜ ์˜ค๋ฅ˜ (order violation)

๋‹ค์Œ์€ ์ˆœ์„œ ์œ„๋ฐ˜ ์˜ค๋ฅ˜์ด๋‹ค. ์•„๋ž˜ ์˜ˆ์‹œ ์ฝ”๋“œ์—์„œ ์–ด๋–ค ๋ถ€๋ถ„์— ์˜ค๋ฅ˜๊ฐ€ ์žˆ๋Š”์ง€ ํ•œ๋ฒˆ ์ฐพ์•„๋ณด์ž.

// Thread 1::
void init() {
	. . .
	mThread = PR_CreateThread(mMain, . . . ) ;
	. . .
}

// Thread 2::
void mMain ( . . . ) {
	. . .
	mState = mThreadโˆ’>State;
	. . .
}

์ด ์ฝ”๋“œ์—์„œ ์“ฐ๋ ˆ๋“œ 2์˜ ์ฝ”๋“œ๋Š” mThread ๋ณ€์ˆ˜๊ฐ€ ์ด๋ฏธ ์ดˆ๊ธฐํ™” + NULL์ด ์•„๋‹˜์„ ๊ฐ€์ •ํ•˜๊ณ  ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ๋งŒ์•ฝ ์“ฐ๋ ˆ๋“œ 1์ด ๋จผ์ € ์‹คํ–‰๋˜์ง€ ์•Š์•˜๋‹ค๋ฉด, ์“ฐ๋ ˆ๋“œ 2๋Š” NULL ํฌ์ธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํฌ๋ž˜์‰ฌ๋  ๊ฒƒ์ด๋‹ค. ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์•„ NULL์ด ์•„๋‹Œ ์ž„์˜์˜ ๋ฉ”๋ชจ๋ฆฌ ์ฃผ์†Œ๋ฅผ ์ ‘๊ทผํ•˜๊ฒŒ ๋˜๋ฉด ๋” ์ด์ƒํ•œ ์ผ์ด ๋ฐœ์ƒํ•  ๊ฒƒ์ด๋‹ค.

๋‘ ๊ฐœ์˜ (๊ทธ๋ฃน์˜) ๋ฉ”๋ชจ๋ฆฌ ์ฐธ์กฐ ๊ฐ„์˜ ์ˆœ์„œ๊ฐ€ ๋ฐ”๋€Œ์—ˆ๋‹ค. ์ฆ‰, A๊ฐ€ ํ•ญ์ƒ B๋ณด๋‹ค ๋จผ์ € ์‹คํ–‰๋˜์–ด์•ผ ํ•˜์ง€๋งŒ ์‹คํ–‰ ์ค‘์— ๊ทธ ์ˆœ์„œ๊ฐ€ ์ง€์ผœ์ง€์ง€ ์•Š์•˜๋‹ค.

์ด๋Ÿฌํ•œ ์˜ค๋ฅ˜๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์ˆœ์„œ๋ฅผ ๊ฐ•์ œํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์•ž์—์„œ ๋…ผ์˜ํ–ˆ๋˜, ์ปจ๋””์…˜ ๋ณ€์ˆ˜๋ฅผ ๋„์ž…ํ•ด์„œ ์ˆœ์„œ๋ฅผ ๊ฐ•์ œํ•ด๋ณด์ž.

pthread_mutex_t mtLock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t mtCond = PTHREAD_COND_INITIALIZER;
int mtInit = 0;

// Thread 1::
void init() {
	. . .
	mThread = PR_CreateThread(mMain, . . . ) ;
	
	// ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๋ฆฌ๋Š” ์‹œ๊ทธ๋„ ์ „๋‹ฌ
	pthread_mutex_lock(&mtLock);
	mtInit = 1;
	pthread_cond_signal(&mtCond);
	pthread_mutex_unlock(&mtLock);
	. . .
}

// Thread 2::
void mMain ( . . . ) {
	. . .
	// ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ดˆ๊ธฐํ™”๋˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฐ๋‹ค
	pthread_mutex_lock(&mtLock);
	while (mtInit == 0)
		pthread_cond_wait(&mtCond, &mtLock);
	pthread_mutex_unlock(&mtLock);
	
	mState = mThreadโˆ’>State;
	. . .
}

mtLock๋ผ๋Š” ๋ฝ, ๊ทธ์— ๋Œ€ํ•œ ์ปจ๋””์…˜ ๋ณ€์ˆ˜ mtCond, ๊ทธ๋ฆฌ๊ณ  ์ƒํƒœ ๋ณ€์ˆ˜ mtInit์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค. ์ดˆ๊ธฐํ™” ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๋ฉด mtInit์˜ ์ƒํƒœ๋ฅผ 1๋กœ ์„ค์ •ํ•˜๊ณ  ์ดˆ๊ธฐํ™”๋ฅผ ์™„๋ฃŒํ–ˆ๋‹ค๊ณ  ์‹œ๊ทธ๋„์„ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค. ๋งŒ์•ฝ ์“ฐ๋ ˆ๋“œ 2๊ฐ€ ์ด ์‹œ์  ์ „์— ์‹คํ–‰๋œ๋‹ค๋ฉด ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜๊ธฐ๋ฅผ ๋Œ€๊ธฐํ•œ๋‹ค. ์ดํ›„์— ๋‹ค์‹œ ์“ฐ๋ ˆ๋“œ 2๊ฐ€ ์‹คํ–‰๋˜๋ฉด ์ƒํƒœ ๊ฐ’ ์ดˆ๊ธฐํ™” ์—ฌ๋ถ€๋ฅผ ๊ฒ€์‚ฌํ•œ ํ›„, (mtInit์ด 1๋กœ ์„ค์ •๋˜์—ˆ๋Š”์ง€ ๊ฒ€์‚ฌํ•œ ํ›„) ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ๊ณ„์† ์ง„ํ–‰ํ•œ๋‹ค.

์ด๋ ‡๊ฒŒ ์“ฐ๋ ˆ๋“œ ๊ฐ„์˜ ์ˆœ์„œ๊ฐ€ ๋ฌธ์ œ๊ฐ€ ๋˜๋Š” ๊ฒฝ์šฐ๋Š” ์ปจ๋””์…˜ ๋ณ€์ˆ˜ (๋˜๋Š” ์„ธ๋งˆํฌ์–ด) ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

์ •๋ฆฌ

๋น„ ๊ต์ฐฉ ์ƒํƒœ ์˜ค๋ฅ˜์˜ ๋Œ€๋ถ€๋ถ„(97%)์€ ์›์ž์„ฑ ๋˜๋Š” ์ˆœ์„œ ์œ„๋ฐ˜์— ๋Œ€ํ•œ ๊ฒƒ์ด์—ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์˜ค๋ฅ˜ ํŒจํ„ด๋“ค์„ ์œ ์˜ํ•˜๋ฉด ๊ด€๋ จ ์˜ค๋ฅ˜๋“ค์„ ์ข€ ๋” ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.

3. ๊ต์ฐฉ ์ƒํƒœ ์˜ค๋ฅ˜

๋ณต์žกํ•œ ๋ฝ ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•˜๋Š” ๋‹ค์ˆ˜์˜ ๋ณ‘ํ–‰ ์‹œ์Šคํ…œ์—์„œ ๊ต์ฐฉ ์ƒํƒœ(deadlock) ๋ผ๋Š” ๊ณ ์ „์  ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ๋ฝ L1์„ ๊ฐ–๊ณ  ์žˆ๋Š” ์“ฐ๋ ˆ๋“œ 2๊ฐ€ ๋ฝ L1์ด ํ•ด์ œ๋˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ์„ ๋•Œ ๊ต์ฐฉ ์ƒํƒœ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ๊ต์ฐฉ ์ƒํƒœ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š” ์ฝ”๋“œ๋ฅผ ๋‹ค์Œ์— ๋‚˜ํƒ€๋‚ด์—ˆ๋‹ค.

Thread 1:     Thread 2:
lock(L1);     lock(L2);
lock(L2);     lock(L1);

์“ฐ๋ ˆ๋“œ 1์ด ๋ฝ L1์„ ํš๋“ํ•œ ํ›„์— ๋ฌธ๋งฅ ๊ตํ™˜์ด ๋ฐœ์ƒํ•˜์—ฌ ์“ฐ๋ ˆ๋“œ 2๊ฐ€ ์‹คํ–‰๋˜๊ณ , ์ด ๋•Œ ์“ฐ๋ ˆ๋“œ 2๊ฐ€ ๋ฝ L2๋ฅผ ํš๋“ํ•˜๊ณ  ๋ฝ L1์„ ํš๋“ํ•˜๋ ค๊ณ  ์‹œ๋„ํ•˜๋ฉด ๊ต์ฐฉ ์ƒํƒœ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

๊ฐ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ƒ๋Œ€๋ฐฉ์ด ์†Œ์œ ํ•˜๊ณ  ์žˆ๋Š” ๋ฝ์„ ๋Œ€๊ธฐํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ˆ„๊ตฌ๋„ ์‹คํ–‰ํ•  ์ˆ˜ ์—†๊ฒŒ ๋œ๋‹ค. OSTEP 32 Concurrency Bugs-1695639772958.jpeg

๊ต์ฐฉ ์ƒํƒœ๋Š” ์™œ ๋ฐœ์ƒํ•˜๋Š”๊ฐ€

์“ฐ๋ ˆ๋“œ 1๊ณผ 2๊ฐ€ ๋ฝ์„ ๊ฐ™์€ ์ˆœ์„œ๋กœ ํš๋“ํ•˜๋„๋ก ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ๊ต์ฐฉ ์ƒํƒœ๋Š” ์ ˆ๋Œ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ด๋ ‡๊ฒŒ ๊ฐ„๋‹จํ•˜๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ ๊ต์ฐฉ ์ƒํƒœ๋Š” ์™œ ๋ฐœ์ƒํ• ๊นŒ?

์ฝ”๋“œ๊ฐ€ ๋งŽ์•„์ง€๋ฉด์„œ ๊ตฌ์„ฑ ์š”์†Œ ๊ฐ„์— ๋ณต์žกํ•œ ์˜์กด์„ฑ์ด ๋ฐœ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์šด์˜์ฒด์ œ๋ฅผ ์˜ˆ๋กœ ๋“ค๋ฉด, ๊ฐ€์ƒ ๋ฉ”๋ชจ๋ฆฌ ์‹œ์Šคํ…œ์ด ๋””์Šคํฌ ๋ธ”๋Ÿญ์„ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด ํŒŒ์ผ ์‹œ์Šคํ…œ์— ์ ‘๊ทผํ•œ๋‹ค. ํŒŒ์ผ ์‹œ์Šคํ…œ์€ ๋””์Šคํฌ ๋ธ”๋Ÿญ์„ ๋ฉ”๋ชจ๋ฆฌ์— ํƒ‘์žฌํ•˜๊ธฐ ์œ„ํ•ด ๋ฉ”๋ชจ๋ฆฌ ํŽ˜์ด์ง€๋ฅผ ํ™•๋ณดํ•ด์•ผ ํ•˜๊ณ , ์ด๋ฅผ ์œ„ํ•ด ๊ฐ€์ƒ ๋ฉ”๋ชจ๋ฆฌ ์‹œ์Šคํ…œ์— ์ ‘๊ทผํ•œ๋‹ค.

๋˜ ๋‹ค๋ฅธ ์ด์œ ๋Š” ์บก์Аํ™”์ด๋‹ค. ์†Œํ”„ํŠธ์›จ์–ด ๋ชจ๋“ˆํ™”๊ฐ€ ๊ฐœ๋ฐœ์„ ์‰ฝ๊ฒŒ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ƒ์„ธํ•œ ๊ตฌํ˜„ ๋‚ด์šฉ์€ ๊ฐ์ถ”๋„๋ก ๊ตฌํ˜„ํ•œ๋‹ค. ํ•˜์ง€๋งŒ ์ด๋Ÿฐ ๋ชจ๋“ˆํ™” ๋•Œ๋ฌธ์— ๊ต์ฐฉ ์ƒํƒœ๊ฐ€ ์ผ์–ด๋‚  ์ˆ˜ ์žˆ๋‹ค.

์ž๋ฐ”์˜ Vector ํด๋ž˜์Šค๋ฅผ ์˜ˆ๋กœ ๋“ค๋ฉด,

Vector v1, v2;
v1.addAll(v2);

์ด ๋ฉ”์†Œ๋“œ๋Š” v1์— ๋Œ€ํ•œ ๋ฝ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ v2์— ๋Œ€ํ•œ ๋ฝ๋„ ํš๋“ํ•ด์•ผ ํ•œ๋‹ค. ํ•˜์ง€๋งŒ ์–ด๋–ค ์“ฐ๋ ˆ๋“œ๊ฐ€ v2.addAll(v1)์„ ํ˜ธ์ถœํ•˜๋ฉด ๊ต์ฐฉ ์ƒํƒœ๊ฐ€ ์ผ์–ด๋‚  ์ˆ˜ ์žˆ๋‹ค.

๊ต์ฐฉ ์ƒํƒœ ๋ฐœ์ƒ ์กฐ๊ฑด

๊ต์ฐฉ ์ƒํƒœ๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋„ค ๊ฐ€์ง€ ์กฐ๊ฑด์ด ์ถฉ์กฑ๋˜์–ด์•ผ ํ•œ๋‹ค.

  • ์ƒํ˜ธ ๋ฐฐ์ œ (Mutual Exclusion): ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ž์‹ ์ด ํ•„์š”๋กœ ํ•˜๋Š” ์ž์›์— ๋Œ€ํ•œ ๋…์ž์ ์ธ ์ œ์–ด๊ถŒ์„ ์ฃผ์žฅํ•œ๋‹ค (์˜ˆ, ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋ฝ์„ ํš๋“ํ•จ).
  • ์ ์œ  ๋ฐ ๋Œ€๊ธฐ (Hold-and-wait): ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ž์‹ ์—๊ฒŒ ํ• ๋‹น๋œ ์ž์› (์˜ˆ : ์ด๋ฏธ ํš๋“ํ•œ ๋ฝ)์„ ์ ์œ ํ•œ ์ฑ„๋กœ ๋‹ค๋ฅธ ์ž์› (์˜ˆ : ํš๋“ํ•˜๊ณ ์ž ํ•˜๋Š” ๋ฝ)์„ ๋Œ€๊ธฐํ•œ๋‹ค.
  • ๋น„ ์„ ์  (No preemption): ์ž์› (๋ฝ)์„ ์ ์œ ํ•˜๊ณ  ์žˆ๋Š” ์“ฐ๋ ˆ๋“œ๋กœ๋ถ€ํ„ฐ ์ž์›์„ ๊ฐ•์ œ์  ์œผ๋กœ ๋นผ์•—์„ ์ˆ˜ ์—†๋‹ค.
  • ์ˆœํ™˜ ๋Œ€๊ธฐ (Circular wait): ๊ฐ ์“ฐ๋ ˆ๋“œ๋Š” ๋‹ค์Œ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์š”์ฒญํ•œ ํ•˜๋‚˜ ๋˜๋Š” ๊ทธ ์ด์ƒ์˜ ์ž์› (๋ฝ)์„ ๊ฐ–๊ณ  ์žˆ๋Š” ์“ฐ๋ ˆ๋“œ๋“ค์˜ ์ˆœํ™˜ ๊ณ ๋ฆฌ๊ฐ€ ์žˆ๋‹ค.

์ด ๋„ค ์กฐ๊ฑด ์ค‘ ํ•˜๋‚˜๋ผ๋„ ๋งŒ์กฑ์‹œํ‚ค์ง€ ์•Š๋Š”๋‹ค๋ฉด, ๊ต์ฐฉ ์ƒํƒœ๋Š” ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.

๊ต์ฐฉ ์ƒํƒœ์˜ ์˜ˆ๋ฐฉ

์ˆœํ™˜ ๋Œ€๊ธฐ

๊ฐ€์žฅ ์‹ค์šฉ์ ์ธ ๋ฐฉ๋ฒ•์ด๋ฉด์„œ ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ๋ฐฉ๋ฒ•์€ ์ˆœํ™˜ ๋Œ€๊ฐ€๊ธฐ ์ ˆ๋Œ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ๋ฝ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

๋ฝ ํš๋“์„ ํ•˜๋Š” ์ „์ฒด ์ˆœ์„œ (total ordering) ์„ ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. L1๊ณผ L2๋ผ๋Š” ๋‘๊ฐœ์˜ ๋ฝ๋งŒ์ด ์‹œ์Šคํ…œ์— ์กด์žฌํ•˜๋ฉด, L1์„ ๋ฌด์กฐ๊ฑด L2 ์ „์— ํš๋“ํ•˜๋„๋ก ํ•˜๋ฉด ๊ต์ฐฉ ์ƒํƒœ๋ฅผ ํ”ผํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด ์ˆœ์„œ๋ฅผ ๋”ฐ๋ฅด๋ฉด ์ˆœํ™˜ ๋Œ€๊ธฐ๋Š” ๋ฐœ์ƒํ•˜์ง€ ์•Š๊ณ , ๋”ฐ๋ผ์„œ ๊ต์ฐฉ ์ƒํƒœ๋„ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.

๋ณต์žกํ•œ ์‹œ์Šคํ…œ์˜ ๊ฒฝ์šฐ ๋ฝ์ด ์—ฌ๋Ÿฌ ๊ฐœ ์กด์žฌํ•  ๊ฒƒ์ด๊ณ , ์ „์ฒด ๋ฝ์˜ ์š”์ฒญ ์ˆœ์„œ๋ฅผ ์ •์˜ํ•˜๋Š” ๊ฒƒ์ด ์–ด๋ ค์šธ ์ˆ˜ ์žˆ๋‹ค. (๋ถˆํ•„์š”ํ•˜๊ธฐ๋„ ํ•˜๋‹ค) ๋•Œ๋ฌธ์— ๋ถ€๋ถ„ ์ˆœ์„œ (partial ordering) ์„ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์ด ๋ฝ ํš๋“ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐ ์œ ์šฉํ•˜๋‹ค.

๋ฝ์˜ ์ˆœ์„œ๋ฅผ ์ •์˜ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ฝ”๋“œ์™€ ๋‹ค์–‘ํ•œ ๋ฃจํ‹ด ๊ฐ„์˜ ์ƒํ˜ธ ํ˜ธ์ถœ ๊ด€๊ณ„๋ฅผ ์ดํ•ดํ•ด์•ผ ํ•œ๋‹ค. ์กฐ๊ธˆ๋งŒ ์‹ค์ˆ˜ํ•ด๋„ ๊ต์ฐฉ ์ƒํƒœ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋œ๋‹ค.

๋ฝ ์ฃผ์†Œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฝ ์š”์ฒญ ์ˆœ์„œ๋ฅผ ๊ฐ•์ œํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ๋‹ค.

if (m1 > m2) { // ๋ฝ์„ ์ฃผ์†Œ์˜ ๋‚ด๋ฆผ์ฐจ์ˆœ์œผ๋กœ ํš๋“
	pthread_mutex_lock(m1);
	pthread_mutex_lock(m2);
} else {
	pthread_mutex_lock(m2);
	pthread_mutex_lock(m1);
}
// m1 != m2๋ฅผ ๊ฐ€์ •

์ ์œ  ๋ฐ ๋Œ€๊ธฐ

์›์ž์ ์œผ๋กœ ๋ชจ๋“  ๋ฝ์„ ํ•œ๋ฒˆ์— ํš๋“ํ•˜๋„๋ก ํ•˜๋ฉด ์ด๋ฅผ ์˜ˆ๋ฐฉํ•  ์ˆ˜ ์žˆ๋‹ค.

lock(prevention);
lock(L1);
lock(L2);
. . .
unlock(prevention);

์ œ์ผ ๋จผ์ € prevention ๋ฝ์„ ํš๋“ํ•˜์—ฌ ๋ฝ์„ ํš๋“ํ•˜๋Š” ๊ณผ์ • ์ค‘์— ์“ฐ๋ ˆ๋“œ์˜ ๋ฌธ๋งฅ ๊ตํ™˜์ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ณ , ๊ฒฐ๊ณผ์ ์œผ๋กœ ๊ต์ฐฉ ์ƒํƒœ์˜ ๋ฐœ์ƒ ๊ฐ€๋Šฅ์„ฑ์„ ์ฐจ๋‹จํ•œ๋‹ค. ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ L1๊ณผ L2๋ฅผ ๋‹ค๋ฅธ ์ˆœ์„œ๋กœ ํš๋“ํ•˜๋ ค๊ณ  ํ•ด๋„ ์ƒ๊ด€ ์—†๋‹ค. prevention ๋ฝ์„ ์ด๋ฏธ ํš๋“ํ•œ ํ›„์— ๋‚˜๋จธ์ง€ ๋ฝ์„ ์š”์ฒญํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์ด ํ•ด๋ฒ•์€ ๋ฌธ์ œ์ ์ด ๋งŽ๋‹ค. ์บก์Аํ™”๊ฐ€ ์–ด๋ ต๋‹ค. ํ•„์š”ํ•œ ๋ฝ์„ ์ •ํ™•ํžˆ ํŒŒ์•…ํ•ด์•ผ ํ•˜๊ณ , ๊ทธ ๋ฝ๋“ค์„ ๋ฏธ๋ฆฌ ํš๋“ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋ฝ์ด ์‹ค์ œ ํ•„์š”ํ•  ๋•Œ ์š”์ฒญํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋ฏธ๋ฆฌ ๋ชจ๋“  ๋ฝ์„ ํ•œ๋ฒˆ์— ํš๋“ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ณ‘ํ–‰์„ฑ์ด ์ €ํ•˜๋˜๋Š” ๋ฌธ์ œ๋„ ์žˆ๋‹ค.

๋น„์„ ์ 

์ผ๋ฐ˜์ ์œผ๋กœ ๋ฝ์„ ํ•ด์ œํ•˜๊ธฐ ์ „๊นŒ์ง€๋Š” ๋ฝ์„ ๋ณด์œ ํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์œผ๋กœ ๋ณด๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๋Ÿฌ ๋ฝ์„ ํš๋“ํ•˜๋Š” ๊ฒƒ์—๋Š” ๋ฌธ์ œ์˜ ์†Œ์ง€๊ฐ€ ๋งŽ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ๋ฝ์„ ์ด๋ฏธ ๋ณด์œ ํ•˜๊ณ  ์žˆ๋Š” ์ฑ„๋กœ ๋‹ค๋ฅธ ๋ฝ์„ ๋Œ€๊ธฐํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋•Œ๋ฌธ์— ๋งŽ์€ ์“ฐ๋ ˆ๋“œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์€ ์ด๋Ÿฌํ•œ ์ƒํ™ฉ์„ ํ”ผํ•  ์ˆ˜ ์žˆ๋„๋ก ์œ ์—ฐํ•œ ์ธํ„ฐํŽ˜์ด์Šค ์ง‘ํ•ฉ์„ ์ œ๊ณตํ•œ๋‹ค. trylock() ๋ฃจํ‹ด์˜ ๊ฒฝ์šฐ ํš๋“ ๊ฐ€๋Šฅํ•˜๋‹ค๋ฉด ๋ฝ์„ ํš๋“ํ•˜๊ฑฐ๋‚˜ ํ˜„์žฌ ๋ฝ์ด ์ ์œ ๋œ ์ƒํƒœ์ด๋‹ˆ ๋‚˜์ค‘์— ๋‹ค์‹œ ์‹œ๋„๋ผํ•˜๋ผ๋Š” ๊ฒƒ์„ ์•Œ๋ฆฌ๋Š” -1์„ ๋ฆฌํ„ดํ•œ๋‹ค.

์ด trylock() ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ด์šฉํ•˜๋ฉด ๊ต์ฐฉ ์ƒํƒœ ๊ฐ€๋Šฅ์„ฑ์ด ์—†๊ณ  ํš๋“ ์ˆœ์„œ์— ์˜ํ–ฅ์„ ๋ฐ›์ง€ ์•Š๋Š” ๋ฝ ํš๋“ ๋ฐฉ๋ฒ•์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

top:
lock(L1);
if (trylock(L2) == โˆ’1) {
	unlock(L1);
	goto top;
}

๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๊ฐ™์€ ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•˜๋ฉด์„œ ๋ฝ์„ ๋‹ค๋ฅธ ์ˆœ์„œ๋กœ ํš๋“ํ•˜๋ ค๊ณ  ํ•ด๋„ ๊ต์ฐฉ ์ƒํƒœ๋Š” ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค. ํ•˜์ง€๋งŒ ๋ฌดํ•œ๋ฐ˜๋ณต(livelock) ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธด๋‹ค.

๋‘ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ด ์ˆœ์„œ๋กœ ๊ณ„์† ์‹œ๋„ํ•˜๋ฉด์„œ ๋ฝ ํš๋“์— ์‹คํŒจํ•˜๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•˜๊ธด ํ•˜๋‹ค. ํ™•๋ฅ ์€ ๋‚ฎ์ง€๋งŒ. ๋ฐ˜๋ณต๋ฌธ์— ์ง€์—ฐ ์‹œ๊ฐ„์„ ๋ฌด์ž‘์œ„๋กœ ์กฐ์ ˆํ•ด์„œ ๊ฒฝ์Ÿํ•˜๋Š” ์“ฐ๋ ˆ๋“œ ๊ฐ„์˜ ๋ฐ˜๋ณต ๊ฐ„์„ญ ํ™•๋ฅ ์„ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.

์ƒํ˜ธ ๋ฐฐ์ œ

๋งˆ์ง€๋ง‰ ์˜ˆ๋ฐฉ ๊ธฐ๋ฒ•์€ ์ƒํ˜ธ ๋ฐฐ์ œ ์ž์ฒด๋ฅผ ์—†์• ๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค. ์ผ๋ฐ˜์ ์ธ ์ฝ”๋“œ๋Š” ๋ชจ๋‘ ์ž„๊ณ„ ์˜์—ญ์„ ํฌํ•จํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Š” ์–ด๋ ค์šด ์ผ์ด๋‹ค.

wait free ์ž๋ฃŒ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค์–ด์„œ ์ด๋ฅผ ํ•ด๊ฒฐํ–ˆ๋‹ค. ๋ช…์‹œ์  ๋ฝ์ด ํ•„์š” ์—†๋Š” ๊ฐ•๋ ฅํ•œ ํ•˜๋“œ์›จ์–ด ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž๋ฃŒ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค๋ฉด ๋˜์ง€ ์•Š์„๊นŒ?

๊ฐ„๋‹จํ•œ ์˜ˆ์ œ๋กœ Compare-And-Swap์ด ์žˆ๋‹ค.

int CompareAndSwap(int *address, int expected, int new) {
	if (*address == expected) {
		*address = new;
		return 1; // ์„ฑ๊ณต
	}
	return 0; // ์‹คํŒจ
}

์–ด๋–ค ํ•œ ๊ฐ’์„ ์›์ž์ ์œผ๋กœ ์ž„์˜์˜ ํฌ๊ธฐ๋งŒํผ ์ฆ๊ฐ€์‹œํ‚ค๋Š” ๊ฒฝ์šฐ๋ฅผ ๊ตฌํ˜„ํ•ด๋ณด์ž.

void AtomicIncrement(int *value, int amount) {
	do {
		int old = *value;
	} while (CompareAndSwap(value, old, old + amount) == 0);
}

๋ฝ์„ ํš๋“ํ•˜์—ฌ ๊ฐ’์„ ๊ฐฑ์‹ ํ•œ ํ›„์— ๋ฝ์„ ํ•ด์ œํ•˜๋Š” ๋Œ€์‹ , Compare-And-Swap ๋ช…๋ น์–ด๋กœ ๊ฐ’์— ์ƒˆ๋กœ์šด ๊ฐ’์„ ๊ฐฑ์‹ ํ•˜๋„๋ก ๋ฐ˜๋ณต์ ์œผ๋กœ ์‹œ๋„ํ•œ๋‹ค. ์ด์™€ ๊ฐ™์€ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฝ์„ ํš๋“ํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฉฐ ๊ต์ฐฉ ์ƒํƒœ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜๋„ ์—†๋‹ค. ๋ฌผ๋ก  ๋ฌดํ•œ ๋ฐ˜๋ณต์€ ๋ฐœ์ƒํ•  ์—ฌ์ง€๊ฐ€ ์žˆ๋‹ค.

์ข€ ๋” ๋ณต์žกํ•œ ์˜ˆ์ œ๋ฅผ ๋ณด์ž. ๋ฆฌ์ŠคํŠธ ํ•ด๋“œ์— ๊ฐœ์ฒด๋ฅผ ์‚ฝ์ž…ํ•˜๋Š” ์ฝ”๋“œ์ด๋‹ค.

void insert(int value) {
	node_t *n = malloc(sizeof(node_t));
	assert(n != NULL);
	n->value = value;
	do {
		n->next = head;
	} while (CompareAndSwap(&head, n->next, n) == 0);
}

next ํฌ์ธํ„ฐ๊ฐ€ ํ˜„์žฌ์˜ ํ—ค๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋„๋ก ๊ฐฑ์‹ ํ•˜๊ณ , ์ƒˆ๋กœ ์ƒ์„ฑ๋œ ๋…ธ๋“œ๋Š” ๋ฆฌ์ŠคํŠธ์˜ ํ—ค๋“œ๊ฐ€ ๋˜๋„๋ก ๋™์ž‘ํ•œ๋‹ค. ์ด ์ฝ”๋“œ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋„์ค‘ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ƒˆ๋กœ์šด ํ—ค๋“œ๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค๋ฉด, Compare-And-Swap์€ ์‹คํŒจํ•˜๊ณ  ์‚ฝ์ž… ๊ณผ์ •์„ ๋‹ค์‹œ ์‹œ๋„ํ•œ๋‹ค.

์ฐธ๊ณ 

์Šค์ผ€์ค„๋ง์œผ๋กœ ๊ต์ฐฉ ์ƒํƒœ ํšŒํ”ผํ•˜๊ธฐ

์˜ˆ๋ฐฉ๋ณด๋‹ค ํšŒํ”ผ๊ฐ€ ๋” ์œ ์šฉํ•  ๋•Œ๊ฐ€ ์žˆ๋‹ค. ๊ต์ฐฉ ์ƒํƒœ๋ฅผ ํšŒํ”ผํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์–ด๋–ค ๋ฝ์„ ํš๋“ํ•˜๊ฒŒ ๋  ๊ฒƒ์ธ์ง€์— ๋Œ€ํ•ด ์ „๋ฐ˜์ ์œผ๋กœ ํŒŒ์•…ํ•˜๊ณ  ์žˆ์–ด์•ผ ํ•˜๋ฉฐ, ๊ทธ๊ฒƒ์„ ๋ฐ”ํƒ•์œผ๋กœ ์“ฐ๋ ˆ๋“œ๋“ค์„ ์Šค์ผ€์ค„๋งํ•˜์—ฌ ๊ต์ฐฉ ์ƒํƒœ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ๊ทธ๋•Œ๊ทธ๋•Œ ๋ณด์žฅํ•œ๋‹ค.

OSTEP 32 Concurrency Bugs-1695644612328.jpeg

4๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ๊ฐ€ ํ”„๋กœ์„ธ์„œ 2๊ฐœ์—์„œ ์‹คํ–‰๋˜๊ณ , ๋ฝ 2๊ฐœ๊ฐ€ ์กด์žฌํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ž. ๋˜‘๋˜‘ํ•œ ์Šค์ผ€์ค„๋Ÿฌ๋ผ๋ฉด T1๊ณผ T2๊ฐ€ ๋™์‹œ์— ์‹คํ–‰๋˜์ง€ ์•Š๋„๋ก ํ•˜์—ฌ ๊ต์ฐฉ ์ƒํƒœ๋ฅผ ํšŒํ”ผํ•  ๊ฒƒ์ด๋‹ค.

OSTEP 32 Concurrency Bugs-1695644689116.jpeg

๋‹ค๋ฅธ ์˜ˆ์‹œ๋„ ํ•œ ๋ฒˆ ์‚ดํŽด๋ณด์ž.

OSTEP 32 Concurrency Bugs-1695644714303.jpeg

์ด ๊ฒฝ์šฐ๋Š” T1, T2, T3์ด ๋™์‹œ์— ์‹คํ–‰๋˜๋ฉด ์•ˆ ๋œ๋‹ค.

OSTEP 32 Concurrency Bugs-1695644733954.jpeg

T1, T2, T3์ด ๋ชจ๋‘ ํ•œ ํ”„๋กœ์„ธ์„œ์—์„œ ์‹คํ–‰๋˜๋„๋ก ๋ณด์ˆ˜์ ์ธ ๋ฐฉ๋ฒ•์„ ํƒํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ „์ฒด ์ž‘์—…์ด ๋๋‚˜๊ธฐ๊นŒ์ง€ ์˜ค๋žœ ์‹œ๊ฐ„์ด ๊ฑธ๋ฆฐ๋‹ค. ๋•Œ๋ฌธ์— ์Šค์ผ€์ค„๋ง์œผ๋กœ ๊ต์ฐฉ ์ƒํƒœ๋ฅผ ํšŒํ”ผํ•˜๋Š” ๊ฒƒ์€ ๋ณดํŽธ์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๋ฐฉ๋ฒ•์€ ์•„๋‹ˆ๋‹ค.

๋ฐœ๊ฒฌ ๋ฐ ๋ณต๊ตฌ

๋งˆ์ง€๋ง‰ ์ „๋žต์€ ๊ต์ฐฉ ์ƒํƒœ ๋ฐœ์ƒ์„ ํ—ˆ์šฉํ•˜๊ณ , ๋ฐœ๊ฒฌํ•˜๋ฉด ๋ณต๊ตฌํ•˜๋„๋ก ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์šด์˜์ฒด์ œ๊ฐ€ 1๋…„์— ํ•œ ๋ฒˆ ๋ฉˆ์ถ˜๋‹ค๊ณ  ํ–ˆ์„ ๋•Œ ์‹œ์›ํ•˜๊ฒŒ ์žฌ๋ถ€ํŒ…์„ ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค. ๊ต์ฐฉ ์ƒํƒœ๊ฐ€ ์•„์ฃผ ๊ฐ€๋” ๋ฐœ์ƒํ•œ๋‹ค๋ฉด ๊ฝค ์œ ์šฉํ•œ ๋ฐฉ๋ฒ•์ด๋‹ค.

๋งŽ์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์‹œ์Šคํ…œ๋“ค์ด ๊ต์ฐฉ ์ƒํƒœ๋ฅผ ๋ฐœ๊ฒฌํ•˜๊ณ  ํšŒ๋ณตํ•˜๋Š” ๊ธฐ์ˆ ์„ ์‚ฌ์šฉํ•œ๋‹ค. ์ด๋Š” ์ฃผ๊ธฐ์ ์œผ๋กœ ์‹คํ–‰๋˜๋ฉฐ ์ž์› ํ• ๋‹น ๊ทธ๋ž˜ํ”„๋ฅผ ๊ทธ๋ ค์„œ ์‚ฌ์ดํด์ด ์ƒ๊ฒผ๋Š”์ง€๋ฅผ ๊ฒ€์‚ฌํ•œ๋‹ค. ์‚ฌ์ดํด์ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ, ์‹œ์Šคํ…œ์€ ์žฌ๋ถ€ํŒ…๋˜์–ด์•ผ ํ•œ๋‹ค.

ํ•ญ์ƒ ์™„๋ฒฝ์„ ์ถ”๊ตฌํ•˜์ง€๋Š” ๋ง์ž. ์•ˆ ์ข‹์€ ์ผ์ด ์•„์ฃผ ๊ฐ€๋” ๋ฐœ์ƒํ•œ๋‹ค๋ฉด, ๊ทธ ์ผ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์•„์ฃผ ๋งŽ์€ ์‹œ๊ฐ„์„ ๋“ค์ผ ํ•„์š”๋Š” ์—†๋‹ค.