μ°λ¦¬κ° λ°°μ΄ βλ½β νλλ§ κ°μ§κ³ λ μ λλ‘ λ³ν νλ‘κ·Έλ¨μ μμ±ν μ μλ€. μ°λ λκ° κ³μ μ§ννκΈ° μ μ νΉμ μ‘°κ±΄μ΄ λ§μ‘±λμλμ§ κ²μ¬κ° νμν κ²½μ°κ° μλ€. μλ₯Ό λ€λ©΄ μμ μ°λ λκ° μμ μ λλλμ§ μ¬λΆλ₯Ό μ νμκ° μλ€. μ΄λ° κ±Έ μ΄λ»κ² ꡬνν μ μμκΉ?
volatile int done = 0;
void *child(void *arg) {
printf(βchild\n β);
done = 1;
return NULL;
}
int main(int argc, char *argv[]) {
printf(βparent: begin\n β);
pthread_t c;
Pthread_create(&c, NULL, child, NULL);
while (done == 0)
; // spin
printf(βparent: end\n β);
return 0;
}
μ΄λ κ² κ³΅μ λ³μλ‘ κ΅¬νν μ μλ€ νμ§λ§ λΆλͺ¨ μ°λ λκ° spin νλ©΄μ μμμ λλΉνκ³ μλ€. μ΄ λ°©λ² λμ λΆλͺ¨ μ°λ λκ° νΉμ μ‘°κ±΄μ΄ λ§μ‘±λ λκΉμ§ μ μλ©΄μ κΈ°λ€λ¦¬λ κ²μ΄ λ μ’λ€.
1. μ μμ 루ν΄λ€
μ‘°κ±΄μ΄ μ°Έμ΄ λ λκΉμ§ κΈ°λ€λ¦¬κΈ° μν΄ μ»¨λμ λ³μλ₯Ό νμ©ν μ μλ€. 컨λμ λ³μλ μΌμ’ μΌ ν μλ£ κ΅¬μ‘°λ‘μ, μ΄λ€ μ€νμ μν (λλ μ΄λ€ 쑰건) κ° μνλ κ²κ³Ό λ€λ₯Ό λ μ°Έμ΄ λκΈ°λ₯Ό κΈ°λ€λ¦¬λ©° μ€λ λκ° λκΈ°ν μ μλ νμ΄λ€. λ€λ₯Έ μ°λ λκ° μνλ₯Ό λ³κ²½μμΌ°μ λ, λκΈ° μ€μ΄λ μ°λ λλ₯Ό κΉ¨μ°κ³ , κ³μ μ§νν μ μλλ‘ νλ€.
pthread_cond_t c; λΌκ³ μ¨μ cκ° μ»¨λμ
λ³μκ° λλλ‘ μ μΈνκ³ μ΄κΈ°ννλ€. 컨λμ
λ³μμλ wait() κ³Ό signal() μ΄λΌλ λ κ°μ§ μ°μ°μ΄ μ‘΄μ¬νλ€.
wait() μ μ°λ λκ° μ€μ€λ‘λ₯Ό μ μ¬μ°κΈ° μν΄ νΈμΆνλ κ²μ΄κ³ , signal()μ μ°λ λκ° λ¬΄μμΈκ°λ₯Ό λ³κ²½νκΈ° λλ¬Έμ μ‘°κ±΄μ΄ μ°Έμ΄ λκΈ°λ₯Ό κΈ°λ€λ¦¬λ©° μ μκ³ μλ μ°λ λλ₯Ό κΉ¨μΈ λ νΈμΆνλ€.
pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m);
pthread_cond_signal(pthread_cond_t *c);
wait()μμ μ μν μ μ mutexλ₯Ό λ§€κ°λ³μλ‘ μ¬μ©νλ€λ κ²μ΄λ€. νΈμΆλ λ mutexλ μ 겨μμλ€κ³ κ°μ νμ. wait()μ μν μ λ½μ ν΄μ νκ³ νΈμΆν μ°λ λλ₯Ό μ¬μ°λ κ²μ΄λ€. μ΄λ€ λ€λ₯Έ μ°λ λκ° μκ·Έλμ 보λ΄μ μ°λ λκ° κΉ¨μ΄λλ©΄, wait()μμ 리ν΄νκΈ° μ μ λ½μ μ¬νλν΄μΌ νλ€.
μ¦, μ‘°κ±΄μ΄ λ§μ‘±λμ΄ μ μμ κΉ¨μ΄λ¬λλΌκ³ λ½μ νλνμ§ λͺ»νλ©΄ λ€μ μ μ λλ κ²μ΄λ€. μ΄λ κ² λ³΅μ‘ν μ΄μ λ μ°λ λκ° μ€μ€λ‘λ₯Ό μ¬μ°λ €κ³ ν λ, κ²½μ 쑰건μ λ°μμ λ°©μ§νκΈ° μν΄μμ΄λ€.
μ΄ν΄λ₯Ό λκΈ° μν΄ μμ λ₯Ό μ΄ν΄λ³΄μ.
int done = 0;
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t c = PTHREAD_COND_INITIALIZER;
void thr_exit() {
Pthread_mutex_lock(&m);
done = 1;
Pthread_cond_signal(&c);
Pthread_mutex_unlock(&m);
}
void *child(void *arg) {
printf(βchild\n β);
thr_exit();
return NULL;
}
void thr_join() {
Pthread_mutex_lock(&m);
while (done == 0)
Pthread_cond_wait(&c, &m);
Pthread_mutex_unlock(&m);
}
int main(int argc, char *argv[]) {
printf(βparent: begin\n β);
pthread_t p;
Pthread_create(&p, NULL, child, NULL);
thr_join();
printf(βparent: end\n β);
return 0;
}
λΆλͺ¨ μ°λ λκ° μ‘°κ±΄μ κ²μ¬ν λ
ifλ¬Έμ΄ μλλΌwhileλ¬Έμ μ¬μ©νλ€.
첫 λ²μ§Έ μΌμ΄μ€
λΆλͺ¨ μ°λ λκ° μμ μ°λ λλ₯Ό μμ±νκ³ , κ³μ μ€ννλ©° thr_join()μ νΈμΆνκ³ , μμ μ°λ λκ° λλκΈ°λ₯Ό κΈ°λ€λ¦¬λ κ²½μ°μ΄λ€. μ΄ κ²½μ° λΆλͺ¨ μ°λ λκ° λ½μ νλνκ³ μμμ΄ λλ¬λμ§ κ²μ¬ν νμ μμμ΄ λλμ§ μμμΌλ―λ‘ wait()μ νΈμΆνμ¬ μ€μ€λ‘λ₯Ό μ μ¬μ°κ³ , λ½μ ν΄μ νλ€. μμ μ°λ λκ° μΆν μ€νλμ΄ thr_exit()μ νΈμΆνμ¬ λΆλͺ¨ μ°λ λλ₯Ό κΉ¨μ΄λ€. νΈμΆνλ wait()μμ λ½μ νλν μ±λ‘ 리ν΄νμ¬ λΆλͺ¨ μ°λ λκ° μ€νλκ³ , λ½μ ν΄μ ν ν μ’
λ£λλ€.
λ λ²μ§Έ μΌμ΄μ€
μμ μ°λ λκ° μμ±λλ©΄μ μ¦μ μ€νλκ³ , done μ 1λ‘ μ€μ νκ³ , μκ³ μλ μ°λ λλ₯Ό κΉ¨μ°κΈ° μν΄ μκ·Έλμ 보λΈλ€. νμ§λ§ μκ³ μλ μ°λ λκ° μκΈ° λλ¬Έμ κ·Έλ₯ 리ν΄νλ€.
κ·Έ ν λΆλͺ¨ μ°λ λκ° μ€νλκ³ thr_join()μ νΈμΆνκ³ doneμ΄ 1μ΄λ―λ‘ λ°λ‘ 리ν΄νλ€.
thr_exit(), thr_join()μ μ€μμ±μ μ΄ν΄ν μ μλλ‘ λͺ κ°μ§ ꡬνμ λ°©μμ μ΄ν΄λ³΄μ.
void thr_exit() {
Pthread_mutex_lock(&m);
Pthread_cond_signal(&c);
Pthread_mutex_unlock(&m);
}
void thr_join() {
Pthread_mutex_lock(&m);
Pthread_cond_wait(&c, &m);
Pthread_mutex_unlock(&m);
}
μ΄λ° μμΌλ‘ μμ±λ κ²½μ°λ λ λ²μ§Έ μΌμ΄μ€, μμ μ°λ λκ° μμ±λ μ¦μ μ€νλμ΄ thr_exit()μ νΈμΆνλ κ²½μ°μ μ λλ‘ μλνμ§ μλλ€. μμ νλ‘μΈμ€κ° μκ·Έλμ 보λ΄μ§λ§, κΉ¨μΈ μ°λ λκ° μμ΄ λ¦¬ν΄λλ€. λΆλͺ¨ μ°λ λλ wait()μ νΈμΆνκ³ κ±°κΈ°μ λ©μΆ°μκ² λλ€.
void thr_exit() {
done = 1;
Pthread_cond_signal(&c);
}
void thr_join() {
if (done == 0)
Pthread_cond_wait(&c);
}
μ΄λ° μμΌλ‘ μμ±λ κ²½μ°, κ²½μ μ‘°κ±΄μ΄ λ°μνλ€. λΆλͺ¨ μ°λ λκ° thr_join()μ νΈμΆνκ³ λμ doneμ΄ 0μΈ κ²μ νμΈνκ³ wait()μ νΈμΆνκΈ° μ§μ μ μΈν°λ½νΈμ κ±Έλ € μμ μ°λ λκ° μ€νλμλ€κ³ ν΄λ³΄μ. μμ μ°λ λλ doneμ 1λ‘ λ³κ²½νκ³ μκ·Έλμ 보λ΄μ§λ§ λκΈ° μ€μΈ μ°λ λκ° μλ€. λ€μ λΆλͺ¨ μ°λ λκ° μ€νλλ©΄, wait()μ νΈμΆνκ³ μ μ λ€μ§λ§ μ무λ κΉ¨μ μ€ μ μλ€.
λ κ°μ§ κ°λ¨ν μμ λ₯Ό ν΅ν΄ 컨λμ λ³μλ₯Ό μ λλ‘ νμ©νκΈ° μν κΈ°λ³Έ μ건μ μ μ μμλ€. μ΄λ²μλ μ’ λ 볡μ‘ν μμ λ₯Ό λ€λ£¨μ΄λ³΄μ.
2. μμ°μ / μλΉμ (μ ν λ²νΌ) λ¬Έμ
λ€μμΌλ‘ μ΄ν΄λ³Ό λκΈ°ν λ¬Έμ λ Dijkstraκ° μ²μ μ μν μμ°μ/μλΉμ(producer/consumer) λ¬Έμ μ΄λ€. μ ν λ²νΌ(bounded λ²νΌ) λ¬Έμ λ‘λ μλ €μ Έ μλ€. lock λμ μΌλ°νλ μΈλ§ν¬μ΄λ₯Ό λ°λͺ
νκ² λ μ΄μ κ° μ΄ λ¬Έμ λλ¬Έμ΄λ€.
μ¬λ¬ κ°μ μμ°μ μ°λ λμ μλΉμ μ°λ λκ° μλ€κ³ νμ. μμ°μλ λ°μ΄ν°λ₯Ό λ§λ€μ΄ λ²νΌμ λ£κ³ , μλΉμλ λ²νΌμμ λ°μ΄ν°λ₯Ό κΊΌλ΄μ΄ μ¬μ©νλ€. μ΄λ¬ν κ΄κ³λ μ€μ λ‘ μμ€ν μμ μμ£Ό μΌμ΄λλ€. μλ₯Ό λ€μ΄ λ©ν° μ°λ λ μΉ μλ²μ κ²½μ° μμ°μλ HTTP μμ²μ μμ ν (μ ν λ²νΌ) μ λ£κ³ , μλΉμ μ°λ λλ μ΄ νμμ μμ²μ κΊΌλ΄μ΄ μ²λ¦¬νλ€.
grep foo file.txt | wc -lμ κ°μ λ¬Έμ₯μ²λΌ νμ΄ν λͺ
λ ΉμΌλ‘ ν νλ‘κ·Έλ¨μ κ²°κ³Όλ₯Ό λ€λ₯Έ νλ‘κ·Έλ¨μκ² μ λ¬ν λλ μ ν λ²νΌλ₯Ό μ¬μ©νλ€. UNIX μμ μΆλ ₯ κ²°κ³Όλ₯Ό UNIX νμ΄ν λΌλ κ³³μΌλ‘ μ μ‘νλ€. νμ΄νμ νμͺ½ λμλ wc νλ‘μΈμ€μ νμ€ μ
λ ₯κ³Ό μ°κ²°λμ΄ μλ€. grep νλ‘μΈμ€κ° μμ°μκ° λκ³ wc νλ‘μΈμ€κ° μλΉμκ° λλ€.
μ ν λ²νΌλ 곡μ μμμ΄κ³ , κ²½μ 쑰건μ λ°μμ λ°©μ§νκΈ° μν΄ λκΈ°νκ° νμνλ€. ν κ°μ μ μλ₯Ό μ¬μ©νκ³ , 곡μ λ²νΌμ κ°μ λ£λ ν¨μ, κ°μ κΊΌλ΄λ ν¨μ λ κ°κ° μλ€.
int buffer;
int count = 0;
void put(int value) {
assert(count == 0);
count = 1;
buffer = value;
}
int get() {
assert(count == 1);
count = 0;
return buffer;
}
cond_t cond;
mutex_t mutex;
void *producer(void *arg) {
int i;
for (i = 0; i < loops; i++) {
Pthread_mutex_lock(&mutex); // p1
if (count == 1) // p2
Pthread_cond_wait(&cond, &mutex); // p3
put(i); // p4
Pthread_cond_signal(&cond); // p5
Pthread_mutex_unlock(&mutex); // p6
}
}
void *consumer(void *arg) {
int i;
for (i = 0; i < loops; i++) {
Pthread_mutex_lock(&mutex); // c1
if (count == 0) // c2
Pthread_cond_wait(&cond, &mutex); // c3
int tmp = get(); // c4
Pthread_cond_signal(&cond); // c5
Pthread_mutex_unlock(&mutex); // c6
printf(β%d\n β, tmp);
}
}
컨λμ
λ³μ νλμ κ·Έκ²κ³Ό μ°κ²°λ mutex λ½μ μ¬μ©νλ λ°©μμ λ¨Όμ μλν΄λ³΄μ.
μμ°μλ λ²νΌκ° λΉ λκΉμ§ κΈ°λ€λ¦°λ€. μλΉμλ λ²νΌκ° μ°¨κΈ°λ₯Ό κΈ°λ€λ¦°λ€. μμ°μμ μλΉμκ° κ° νλμ©μΈ κ²½μ°μ μμ μ½λλ μ μμ μΌλ‘ λμνλ€. νμ§λ§ μμ°μ, μλΉμκ° λ κ° μ΄μμ© μ‘΄μ¬νλ κ²½μ°μλ λ¬Έμ κ° μλ€.
첫 λ²μ§Έ λ¬Έμ
λκΈ° λͺ
λ Ή μ μ if λ¬Έκ³Ό κ΄λ ¨μ΄ μλ€.
Tc1 κ³Ό Tc2 λΌλ λ κ°μ μλΉμκ° μκ³ Tp λΌλ μμ°μκ° νλ μλ€κ³ κ°μ νμ. μλΉμ (Tc1)κ° λ¨Όμ μ€νλλ€. λ½ (c1) μ νλνκ³ λ²νΌλ₯Ό μλΉν μ μλμ§ κ²μ¬νλ€ (c2). κ·Έλ¦¬κ³ λΉμ΄μμμ νμΈν νμ λκΈ°νλ©° (c3) λ½μ ν΄μ νλ€. κ·Έλ¦¬κ³ μμ°μ (Tp)κ° μ€νλλ€. λ½μ νλνκ³ (p1) λ²νΌκ° λΉμλμ§ νμΈνλ€ (p2). λΉμμμ λ°κ²¬νκ³ , λ²νΌλ₯Ό μ±μ΄λ€ (p4). μμ°μλ λ²νΌκ° κ°λ μ°Όλ€λ μκ·Έλμ 보λΈλ€ (p5). λκΈ° μ€μΈ 첫째 μλΉμ (Tc1)λ κΉ¨μ΄λ μ€λΉ ν (ready queue)λ‘ μ΄λνλ€. Tc1 μ μ΄μ μ€νν μ μλ μνμ΄μ§λ§ μμ§ μ€ν μνλ μλλ€. μμ°μλ μ€νμ κ³μνλ€. λ²νΌκ° μ°¨ μμΌλ―λ‘ λκΈ° μνλ‘ μ μ΄νλ€ (p6, p1-p3).
μ¬κΈ°μμ λ¬Έμ κ° λ°μνλ€. λ€λ₯Έ μλΉμ (Tc2)κ° λΌμ΄λ€μ΄μ μ€ννλ©΄μ λ²νΌ κ°μ μλΉνλ€ (c1, c2, c4, c5, c6μ μν, c3μ λ²νΌκ° κ°λ μ°ΌκΈ° λλ¬Έμ 건λλ). Tc1 μ΄ μ€νλλ€κ³ ν΄λ³΄μ. λκΈ°μμ 리ν΄νκΈ° μ μ λ½μ νλνλ€. κ·Έλ¦¬κ³ get()μ νΈμΆνμ§λ§ (c4) λ²νΌλ λΉμλ€! μ½λλ μλν λλ‘ κΈ°λ₯νμ§ λͺ»νλ€. μμ°μκ° λ²νΌμ λ£μ΄ λ κ°μ Tc2 κ° λΌμ΄λ€μ΄μ μλΉνμκΈ° λλ¬Έμ Tc1 μ΄ λΉμ΄ μλ λ²νΌλ₯Ό μ½λ νμλ₯Ό λ§μμ΄μΌ νλ€.
λ¬Έμ μ μμΈμ Tc1μ΄ κΉ¨μ΄λμ μ€νλκΈ°κΉμ§μ μ¬μ΄μ μ ν λ²νΌμ μνκ° λ³κ²½λμκΈ° λλ¬Έμ΄λ€. μκ·Έλμ μ°λ λλ₯Ό κΉ¨μ°κΈ°λ§ νκ³ , κΉ¨μ΄λ μ°λ λκ° μ€μ μ±νλλ μμ μ κ·Έ μνκ° μ μ§λλ€λ 보μ₯μ μλ€. μ΄λ° μμΌλ‘ μκ·Έλμ μ μνλ κ²μ Mesa Semanticμ΄λΌ νλ€. λλΉλλ κ°λ μ Hoare SemanticμΈλ° ꡬννκΈ°λ λ μ΄λ ΅μ§λ§ κΉ¨μ΄λ μ¦μ μ°λ λκ° μ€νλλ κ²μ 보μ₯νλ€.
ν΄κ²° λ°©λ²: if -> while
if λ¬Έμ while λ¬ΈμΌλ‘ λ³κ²½νλ©΄ μ΄ λ¬Έμ λ₯Ό ν΄κ²°ν μ μλ€.
cond_t cond;
mutex_t mutex;
void *producer(void *arg) {
int i;
for (i = 0; i < loops; i++) {
Pthread_mutex_lock(&mutex); // p1
while (count == 1) // p2
Pthread_cond_wait(&cond, &mutex); // p3
put(i); // p4
Pthread_cond_signal(&cond); // p5
Pthread_mutex_unlock(&mutex); // p6
}
}
void *consumer(void *arg) {
int i;
for (i = 0; i < loops; i++) {
Pthread_mutex_lock(&mutex); // c1
while (count == 0) // c2
Pthread_cond_wait(&cond, &mutex); // c3
int tmp = get(); // c4
Pthread_cond_signal(&cond); // c5
Pthread_mutex_unlock(&mutex); // c6
printf(β%d\n β, tmp);
}
}
μλΉμ Tc1 μ΄ κΉ¨μ΄λμ (λ½μ νλν μν), μ¦μ 곡μ λ³μμ μνλ₯Ό μ¬νμΈνλ€ (c2). λ§μ½ μ΄ μμ μ λ²νΌκ° λΉμ΄ μλ€λ©΄, μλΉμλ λκΈ° μνλ‘ λμκ°λ€ (c3). λ¬Έμ κ° ν΄κ²°λμλ€. Mesa semanticμ 컨λμ λ³μμμ κ°μ₯ κΈ°λ³Έμ μΈ λ²μΉμ μΈμ λ while λ¬Έμ μ¬μ©νλΌλ κ²μ΄λ€.
λ λ²μ§Έ λ¬Έμ
μ΄ λ¬Έμ λ μλΉμ μ°λ λ Tc1 κ³Ό Tc2 κ° λ¨Όμ μ€νν νμ λ λ€ λκΈ° μνμ μμ λ λ°μνλ€ (c3).
μμ°μκ° μ€νλμ΄ λ²νΌμ κ°μ λ£κ³ λκΈ° μ€μΈ μ°λ λ νλλ₯Ό κΉ¨μ°κ³ (Tc1 μ κΉ¨μ λ€κ³ νμ), μμ μ λκΈ°νλ€. μ΄μ νλμ μλΉμ (Tc1)κ° μ€νν μ€λΉκ° λμκ³ μ‘°κ±΄μ μν΄ Tc2 μ Tp λ λκΈ° μ€μ΄λ€. μ΄μ λ¬Έμ κ° λ°μνλλ‘ λ§λ€ κ²μ΄λ€.
μλΉμ Tc1μ΄ wait()μμ 리ν΄μ λ°μ κΉ¨μ΄λκ³ (c3) 쑰건μ μ¬νμΈνλ€ (c2). λ²νΌκ° μ°¨μλ€λ κ²μ λ°κ²¬νκ³ κ°μ μλΉνλ€ (c4). μ΄ μλΉμλ μκ·Έλμ μ μ‘νμ¬ (c5) λκΈ°μ€μΈ μ°λ λ μ€ νλλ₯Ό κΉ¨μ΄λ€. μ΄λ μ΄λ€ μ°λ λλ₯Ό κΉ¨μΈ κ²μΈκ°?
μλΉμκ° λ²νΌλ₯Ό λΉμ κΈ° λλ¬Έμ μμ°μλ₯Ό λΉμ°ν κΉ¨μμΌ νλ€. νμ§λ§, λ§μ½ μλΉμ Tc2 λ₯Ό κΉ¨μ΄λ€λ©΄ (λκΈ° νκ° μ΄λ»κ² κ΄λ¦¬λλλμ λ°λΌ λΉμ°ν λ°μν μ μλ€), λ¬Έμ κ° λ°μνλ€. μλΉμ Tc2 κ° κΉ¨μ΄λλ©΄ λ²νΌκ° λΉμ΄ μλ€λ κ²μ λ°κ²¬ν νμ (c2) λ€μ λκΈ° μνλ‘ λ€μ΄κ°λ€ (c3). λ²νΌμ κ°μ λ£μ΄μΌ νλ μμ°μ Tp λ λκΈ° μ€μ΄λ€. λ€λ₯Έ μλΉμ μ°λ λ Tc1 μμ λκΈ° μνμ λ€μ΄κ°λ€. μΈ κ°μ μ°λ λκ° λͺ¨λ λκΈ° μνλ€.
μκ·Έλμ 보λ΄λ κ²μ κΌ νμνμ§λ§ λμμ΄ λͺ νν΄μΌ νλ€. μλΉμλ λ€λ₯Έ μλΉμλ₯Ό κΉ¨μΈ μ μκ³ μμ°μλ§ κΉ¨μμΌ νλ©°, λ°λλ‘ μμ°μμ κ²½μ°λ λ§μ°¬κ°μ§λ€
λ¨μΌ λ²νΌ μμ°μ/μλΉμ ν΄λ²
λ κ°μ 컨λμ λ³μλ₯Ό μ¬μ©νμ¬ μμ€ν μ μνκ° λ³κ²½λμμ λ κΉ¨μμΌ νλ μ°λ λμκ²λ§ μκ·Έλμ μ λλ‘ μ λ¬νλ€.
cond_t empty, fill;
mutex_t mutex;
void *producer(void *arg) {
int i;
for (i = 0; i < loops; i++) {
Pthread_mutex_lock(&mutex); // p1
while (count == 1) // p2
Pthread_cond_wait(&empty, &mutex); // p3
put(i); // p4
Pthread_cond_signal(&fill); // p5
Pthread_mutex_unlock(&mutex); // p6
}
}
void *consumer(void *arg) {
int i;
for (i = 0; i < loops; i++) {
Pthread_mutex_lock(&mutex); // c1
while (count == 0) // c2
Pthread_cond_wait(&fill, &mutex); // c3
int tmp = get(); // c4
Pthread_cond_signal(&empty); // c5
Pthread_mutex_unlock(&mutex); // c6
printf(β%d\n β, tmp);
}
}
μ΅μ’ μ μΈ μμ°μ/μλΉμ ν΄λ²
λ§μ§λ§ λ³κ²½μ ν΅ν΄ λ³νμ±μ μ¦κ°μν€κ³ ν¨μ¨μ μΌλ‘ λ§λ€μ΄ 보μ. λ²νΌ 곡κ°μ μΆκ°νμ¬ λκΈ° μνμ λ€μ΄κ°κΈ° μ μ μ¬λ¬ κ°λ€μ΄ μμ°λ μ μλλ‘ νλ κ², κ·Έλ¦¬κ³ λ§μ°¬κ°μ§λ‘ μ¬λ¬ κ°μ κ°μ΄ λκΈ° μν μ μ μμ°λ μ μλλ‘ νλ κ²μ΄λ€.
μ°μ λ€μκ³Ό κ°μ΄ λ²νΌ ꡬ쑰μ put(), get() ν¨μλ₯Ό λ³κ²½νμλ€.
int buffer[MAX];
int fill = 0;
int use = 0;
int count = 0;
void put(int value) {
buffer[fill] = value;
fill = (fill + 1) % MAX;
count++;
}
int get() {
int tmp = buffer[use];
use = (use + 1) % MAX;
countββ;
return tmp;
}
μμ°μμ μλΉμμ λκΈ° μν λ‘μ§λ λ³κ²½νμλ€.
cond_t empty, fill;
mutex_t mutex;
void *producer(void *arg) {
int i;
for (i = 0; i < loops; i++) {
Pthread_mutex_lock(&mutex); // p1
while (count == MAX) // p2
Pthread_cond_wait(&empty, &mutex); // p3
put(i); // p4
Pthread_cond_signal(&fill); // p5
Pthread_mutex_unlock(&mutex); // p6
}
}
void *consumer(void *arg) {
int i;
for (i = 0; i < loops; i++) {
Pthread_mutex_lock(&mutex); // c1
while (count == 0) // c2
Pthread_cond_wait(&fill, &mutex); // c3
int tmp = get(); // c4
Pthread_cond_signal(&empty); // c5
Pthread_mutex_unlock(&mutex); // c6
printf(β%d\n β, tmp);
}
}
μμ°μλ λͺ¨λ λ²νΌκ° νμ¬ κ°λ μ°¨ μλ€λ©΄ λκΈ° μνμ λ€μ΄κ°κ³ , μλΉμλ λͺ¨λ λ²νΌκ° λΉμ΄ μλ€λ©΄ λκΈ°μ λ€μ΄κ°λ€.
3. 컨λμ λ³μ μ¬μ© μ μ£Όμμ
ν : 쑰건μ while λ¬Έμ μ¬μ©νμ (if λ¬Έμ μλλ€) λ©ν° μ°λ λ νλ‘κ·Έλ¨μμ 쑰건μ κ²μ¬ν λμλ νμ while λ¬Έμ μ¬μ©νλ κ²μ΄ μ³λ€. μκ·Έλ μ λ¬μ μλ―Έμ λ°λΌ if λ¬Έμ μ¬μ©νλ κ²μ λ§μ μλ μμ λΏμ΄λ€. κ·Έλ¬ λ―λ‘ νμ while λ¬Έμ μ¬μ©νμ, κ·Έλ¬λ©΄ μμ±ν μ½λκ° μλν λλ‘ λμν κ²μ΄λ€. 쑰건 κ²μ¬μ while λ¬Έμ μ¬μ©νλ κ²μ κ±°μ§μΌλ‘ κΉ¨μ΄ κ²½μ° (spurious wakeup) μ λμ²ν μ μλλ‘ ν΄ μ€λ€. μ΄λ€ μ°λ λ ν¨ν€μ§λ ꡬνμμ λ¬Έμ λ‘ νλμ μκ·Έλμ μν΄μ λ κ°μ μ°λ λκ° κΉ¨μ΄λλ κ²½μ°λ κ°λ₯νλ€. μ°λ λκ° μ‘°κ±΄μ μ¬κ²μ¬ν΄μΌ νλ μ΄μ λ κ±°μ§μΌλ‘ κΉ¨μ΄ κ²½μ°κ° μκΈ° λλ¬Έμ΄λ€.
// λͺ byteλ νμ΄ λΉμλκ°?
int bytesLeft = MAX_HEAP_SIZE;
cond_t c;
mutex_t m;
void *allocate(int size) {
Pthread_mutex_lock(&m);
while (bytesLeft < size)
Pthread_cond_wait(&c, &m);
void *ptr = . . . ; // νμμ λ©λͺ¨λ¦¬λ₯Ό ν λΉ λ°μ
bytesLeft β= size;
Pthread_mutex_unlock(&m);
return ptr;
}
void free(void *ptr, int size) {
Pthread_mutex_lock(&m);
bytesLeft += size;
Pthread_cond_signal(&c); // μκ·Έλ μ λ¬ λμμ?..
Pthread_mutex_unlock(&m);
}
λ©ν° μ°λ λ κΈ°λ° λ―Έλͺ¨λ¦¬ ν λΉ λΌμ΄λΈλ¬λ¦¬ μμ μ΄λ€. λ©λͺ¨λ¦¬ ν λΉ μ½λλ₯Ό νΈμΆνλ©΄, 곡κ°μ΄ μκΈΈ λκΉμ§ κΈ°λ€λ €μΌ ν μ μλ€. λ μ°λ λκ° λ©λͺ¨λ¦¬ λ°λ©μ μ¬μ© κ°λ₯ν λ©λͺ¨λ¦¬ 곡κ°μ λ°μμ μ리λ μκ·Έλμ μμ±ν μ μλ€. νμ§λ§ μ΄ μ½λμλ λ¬Έμ κ° μλ€ μ΄λ€ μ°λ λκ° κΉ¨μ΄λμΌ ν κΉ?
μ°λ λ Taλ 100μ ν λΉλ°κΈΈ μνκ³ , μ°λ λ Tbλ 10μ ν λΉλ°κΈΈ μνλ μνμμ, μ΄λ€ μ°λ λκ° 50λ§νΌ λ©λͺ¨λ¦¬λ₯Ό λ°νν κ²½μ°, Taκ° κΉ¨μ΄λλ©΄ μ λκ³ Tbκ° κΉ¨μ΄λμΌ νλ€. μ΄λ° λ¬Έμ λ λ κ°μ 컨λμ λ³μλ₯Ό μ¬μ©ν΄λ ν΄κ²°ν μ μλ€.
Lampsonκ³Ό Redellμ΄ μ μν ν΄λ²μ λ¨μνλ€. pthread_cond_signal()μ λκΈ° μ€μΈ λͺ¨λ μ°λ λλ₯Ό κΉ¨μ°λ pthread_cond_broadcast()λ‘ λ°κΏμ μ¬μ©νλ©΄ λλ€. κ·Έλ κ² ν¨μΌλ‘μ¨ κΉ¨μ΄λμΌ ν μ°λ λκ° μλ€λ©΄ κΉ¨μ΄λ μ μλλ‘ νλ€. κ·Έλ κ² κΉ¨μ΄λ μ°λ λλ€μ κΉ¨μ΄λμ 쑰건μ μ¬κ²μ¬νκ³ , μ¦μ λκΈ° μνλ‘ λ€μ λ€μ΄κ°λ€.
Lampsonκ³Ό Redellμ μ΄λ° κ²½μ°λ₯Ό ν¬ν¨ 쑰건(covering condition)μ΄λΌκ³ νλ€. μλνλ©΄ (보μμ μΌλ‘) μ°λ λκ° κΉ¨μ΄λμΌ νλ λͺ¨λ κ²½μ°λ₯Ό λ€ ν¬ν¨νκΈ° λλ¬Έμ΄λ€. λΆνμνκ² λ§μ μ°λ λκ° κΉ¨μ΄λλ λ¨μ μ΄ μλ€. λ¬Έλ§₯ μ ν μ€λ²ν€λκ° ν¬λ€. μ리ν λ μλΌλ©΄ μ΄ λ°©λ²μ μμμ μ¬μ©νμ μλ μλ€λ κ²μ μ κ²μ΄λ€ (컨λμ λ³μλ₯Ό νλλ§ μ¬μ©νλ μμ°μ/μλΉμ λ¬Έμ λ₯Ό 보μ). νμ§λ§ κ·Έ κ²½μ°μλ λ μ’μ ν΄λ²μ΄ μμκΈ° λλ¬Έμ κ·Έ λ°©λ²μ ννᨩλ€. μΌλ°μ μΌλ‘ μκ·Έλμ λΈλ‘λμΊμ€νΈ (broadcast)λ‘ λ°κΏ¨μ λλ§ νλ‘κ·Έλ¨μ΄ λμνλ€λ©΄ μλ§λ λ²κ·Έκ° μ‘΄μ¬νλ κ²μΌ κ±°λ€. μμ λ€λ£¬ λ©λͺ¨λ¦¬ ν λΉ λ¬Έμ μ κ²½μ° λΈλ‘λμΊμ€νΈλ₯Ό μ μ©νλ κ²μ΄ κ°μ₯ μλͺ ν ν΄λ²μ΄λ€.