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