Search
๐Ÿ’พ

19 : Common Concurrency Problems

course
last review
mastery
none
progress
not started
date
2023/05/11
4 more properties
Previous chapter

Concurrency Problems

โ€ข
Non-deadlock bugs : ๋น„๊ต์ฐฉ์ƒํƒœ ๋ฒ„๊ทธ
โ—ฆ
Atomicity-violation bugs :
โ—ฆ
Order-violation bugs :
โ€ข
Deadlock bugs : ๊ต์ฐฉ์ƒํƒœ ๋ฒ„๊ทธ

Non-deadlock bugs

Atomicity-violation bugs

Thread 1: if (thd->proc_info) { ... fputs(thd->proc_info, ...); ... } Thread 2: thd->proc_info = NULL;
C
๋ณต์‚ฌ
Thread1์™€ Thread 2๊ฐ€ ๋™์‹œ์— ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋‹ค.
โ€ข
Thread1์ด ๋จผ์ € ์‹คํ–‰๋  ๊ฒฝ์šฐ, fputs๊ฐ€ ์‹คํ–‰๋œ ํ›„, Thread2๊ฐ€ NULL์ด ๋œ๋‹ค.
โ€ข
Thread2๊ฐ€ ๋จผ์ € ์‹คํ–‰๋  ๊ฒฝ์šฐ, thdโ†’proc_info = NULL์ด ์‹คํ–‰๋œ ํ›„, Thread1์ด ์‹คํ–‰๋˜์–ด dereference๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ˆ˜์ •ํ•˜์ž.
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);
C
๋ณต์‚ฌ
mutex ๋ณ€์ˆ˜๋ฅผ ์„ ์–ธํ•ด์„œ ๋ฌธ์ œ ํ•ด๊ฒฐ ๊ฐ„์‘!

Order-Violation Bugs

์ˆœ์„œ๊ฐ€ ํ•ญ์ƒ ์ผ๊ด€์ ์ด์ง€ ์•Š๊ณ  ์—ญ์ „๋˜์—ˆ์„ ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ์ 
Thread 1: void init() { ... mThread = PR_CreateThread(mMain, ...); ... } Thread 2: void mMain(...) { ... mState = mThread->State; ... }
C
๋ณต์‚ฌ
mThread๋กœ ๊ฐ’์ด ๋ฆฌํ„ด๋˜์ง€ ์•Š์€ ์ƒํ™ฉ์—์„œ Thread2๊ฐ€ ์‹œ์ž‘๋  ๊ฒฝ์šฐ, NULL-ํฌ์ธํ„ฐ dereference๊ฐ€ ์ผ์–ด๋‚  ์ˆ˜ ์žˆ๋”ฐ.
pthread_mutex_t mtLock = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t mtCond = PTHREAD_COND_INITIALIZER; //fair with muxet lock! int mtInit = 0; Thread 1: void init() { ... mThread = PR_CreateThread(mMain, ...); // signal that the thread has been created... pthread_mutex_lock(&mtLock); mtInit = 1; pthread_cond_signal(&mtCond); pthread_mutex_unlock(&mtLock); ... } Thread 2: void mMain(...) { ... // wait for the thread to be initialized... pthread_mutex_lock(&mtLock); while (mtInit == 0) pthread_cond_wait(&mtCond, &mtLock); pthread_mutex_unlock(&mtLock); mState = mThread->State; ... }
C
๋ณต์‚ฌ

Deadlock Bugs

โ€ข
Circular Dependency
Thread 1: pthread_mutex_lock(L1); pthread_mutex_lock(L2); Thread 2: pthread_mutex_lock(L2); pthread_mutex_lock(L1);
C
๋ณต์‚ฌ
์Šค๋ ˆ๋“œ1์—์„œ L1๋ฝ, ์Šค๋ ˆ๋“œ2์—์„œ L2๋ฝ, ์ดํ›„ ๊ฐ๊ฐ L2์™€ L1์„ ๊ธฐ๋‹ค๋ฆฌ๊ฒŒ ๋˜๋Š”๋ฐ, ๋ฌดํ•œ ๋Œ€๊ธฐ ์ƒ์„ฑ

why deadlock occur?

Condition for deadlock

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

Prevention : Circular wait

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

Prevention : Hold-and-wait

์ ์œ  ๋ฐ ๋Œ€๊ธฐ๋Š” ์›์ž์ ์œผ๋กœ ๋ชจ๋“  ๋ฝ์„ ๋‹จ๋ฒˆ์— ํš๋“ํ•˜๋„๋ก ํ•˜๋ฉด ์˜ˆ๋ฐฉํ•  ์ˆ˜ ์žˆ๋‹ค.
pthread_mutex_lock(prevention); // begin lock acquisition pthread_mutex_lock(L1); pthread_mutex_lock(L2); ... pthread_mutex_unlock(prevention); // end
C
๋ณต์‚ฌ
๋‹ค๋งŒ ๋ฝ์˜ ๊ฐœ์ˆ˜๊ฐ€ ๋งŽ์•„์งˆ ์ˆ˜๋ก ์ง๋ ฌํ™”์˜ ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์•„์ง„๋‹ค๋Š” ์‚ฌ์‹ค์„ ์ฃผ์˜ํ•˜๋ผ.
L1,L2๊ฐ€ ํ•„์š”ํ•œ ์Šค๋ ˆ๋“œ, L3,L4๊ฐ€ ํ•„์š”ํ•œ ์Šค๋ ˆ๋“œ ๋ชจ๋‘ prevention๋ฎคํ…์Šค๋ฅผ ๊ณต์œ ํ•˜๋ฏ€๋กœ, ์ง๋ ฌํ™”๊ฐ€ ๋œ๋‹ค.

Prevention : No preemption

pthread_mutex_trylock() top: pthread_mutex_lock(L1); if (pthread_mutex_trylock(L2) != 0) { pthread_mutex_unlock(L1); goto top; }
C
๋ณต์‚ฌ
preemption์˜ ๋ฐฉ์‹์„ ์šด์˜์ฒด์ œ๊ฐ€ ์•„๋‹Œ ์‘์šฉํ”„๋กœ๊ทธ๋žจ์—๊ฒŒ ์ „๊ฐ€ํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.
trylock์€ waitํ•˜์ง€ ์•Š๊ณ  ๋ฝ์˜ ์„ฑ๊ณต ์—ฌ๋ถ€๋ฅผ ๋ฆฌํ„ดํ•œ๋‹ค.
๋‹ค๋งŒ livelock์ด๋ผ๋Š” ํ˜„์ƒ์ด ์ƒ๊ธธ ์ˆ˜ ์žˆ๋‹ค. ๊ณ„์† ๋ฝ์„ ์‹œ๋„ํ•˜์ง€๋งŒ, ์ง€์†์ ์œผ๋กœ ์‹คํŒจํ•ด์„œ deadlock๊ณผ ์œ ์‚ฌํ•œ ํ˜„์ƒ์ด ์ƒ๊ธธ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ฃผ์˜ํ•˜์ž.
โ€ข
์ด๋Š” ๋ฃจํ”„๊ฐ€ ๋๋‚œ ํ›„์˜ ๋”œ๋ ˆ์ด๋ฅผ ๋žœ๋ค์œผ๋กœ ๋”ํ•˜๋ฉด ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

Prevention : Mutual exclusion

์ œํ•œ์ ์ธ ์˜์—ญ์—๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
Lock-free approaches
int CompareAndSwap(int *address, int expected, int new) { if (*address == expected) { *address = new; return 1; // success } return 0; // failure }
C
๋ณต์‚ฌ
void AtomicIncrement(int *value, int amount) { do { int old = *value; } while (CompareAndSwap(value, old, old + amount) == 0); }
C
๋ณต์‚ฌ
void insert(int value) { node_t *n = malloc(sizeof(node_t)); assert(n != NULL); n->value = value; n->next = head; head = n; }
C
๋ณต์‚ฌ
C
๋ณต์‚ฌ
Next chapter