๋ค์ํ ๋ฒ์ฃผ์ ๋ณํ์ฑ ๋ฌธ์ ํด๊ฒฐ์ ์ํด์๋ ๋ฝ๊ณผ ์กฐ๊ฑด ๋ณ์ ๋ ๋ค ํ์ํ๋ค. ์ด๋ฒ ์ฅ์์ ๋ค๋ฃฐ ์ธ๋งํฌ์ด๋ ๋ฝ๊ณผ ์ปจ๋์ ๋ณ์๋ก ๋ชจ๋ ์ฌ์ฉํ ์ ์๋ค.
ํต์ฌ ์ง๋ฌธ : ์ธ๋งํฌ์ด๋ฅผ ์ด๋ป๊ฒ ์ฌ์ฉํ๋๊ฐ ๋ฝ๊ณผ ์ปจ๋์ ๋ณ์ ๋์ ์ ์ธ๋งํฌ์ด๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ฌด์์ธ๊ฐ? ์ธ๋งํฌ์ด์ ์ ์๋ ๋ฌด์์ธ๊ฐ? ์ด์ง ์ธ๋งํฌ์ด๋ ๋ฌด์์ธ๊ฐ? ๋ฝ๊ณผ ์ปจ๋์ ๋ณ์๋ฅผ ์ฌ์ฉํ์ฌ ์ธ๋งํฌ์ด๋ฅผ ๋ง๋๋ ๊ฒ์ด ๊ฐ๋ฅํ๊ฐ? ๊ทธ ๋ฐ๋๋ก ์ธ๋งํฌ์ด๋ฅผ ์ฌ์ฉํ์ฌ ๋ฝ๊ณผ ์กฐ๊ฑด ๋ณ์๋ฅผ ๋ง๋๋ ๊ฒ์ด ๊ฐ๋ฅํ๊ฐ?
1. ์ธ๋งํฌ์ด: ์ ์
์ธ๋งํฌ์ด๋ ์ ์ ๊ฐ์ ๊ฐ๋ ๊ฐ์ฒด๋ก์ ๋ ๊ฐ์ ๋ฃจํด์ผ๋ก ์กฐ์ํ ์ ์๋ค. POSIX ํ์ค์์ ์ด ๋ ๊ฐ์ ๋ฃจํด์ sem_wait(), sem_post()์ด๋ค. ์ธ๋งํฌ์ด๋ ์ด๊น๊ฐ์ ์ํด ๋์์ด ๊ฒฐ์ ๋๊ธฐ ๋๋ฌธ์ ์ฌ์ฉ ์ ์ ์ด๊ธฐํ๋ฅผ ํด์ผ ํ๋ค.
#include <semaphore.h>
sem_t s;
sem_init(&s, 0, 1);
์ธ๋งํฌ์ด s๋ฅผ ์ ์ธ ํ 3๋ฒ์งธ ์ธ์๋ก 1์ ์ ๋ฌํ์ฌ ์ธ๋งํฌ์ด์ ๊ฐ์ 1๋ก ์ด๊ธฐํํ๋ค. sem_init()์ ๋ ๋ฒ์งธ ์ธ์๋ ๋ชจ๋ ์์ ์์ 0์ด๋ค. ์ด ๊ฐ์ ๊ฐ์ ํ๋ก์ธ์ค ๋ด์ ์ฐ๋ ๋ ๊ฐ์ ์ธ๋งํฌ์ด๋ฅผ ๊ณต์ ํ๋ค๋ ๋ป์ด๋ค. ๋ค๋ฅธ ๊ฐ์ ์ฌ์ฉํ๋ ์์ (๋ค๋ฅธ ํ๋ก์ธ์ค๊ฐ ๋๊ธฐํ ์ ๊ณต) ๋ docs๋ฅผ ์ฝ์ด๋ณด์.
์ด๊ธฐํ๋ ํ์๋ sem_wait(), sem_post()๋ผ๋ ํจ์๋ฅผ ํธ์ถํ์ฌ ์ธ๋งํฌ์ด๋ฅผ ๋ค๋ฃฐ ์ ์๋ค.
int sem_wait(sem_t *s) {
decrement the value of semaphore s by one;
wait if value of semaphore s is negative;
}
int sem_post(sem_t *s) {
increment the value of semaphore s by one;
if there are one or more threads waiting, wake one;
}
sem_wait()ํจ์๋ ์ฆ์ ๋ฆฌํดํ๊ฑฐ๋ (์ธ๋งํฌ์ด์ ๊ฐ์ด 1 ์ด์์ด๋ฉด), ์๋๋ฉด ํด๋น ์ธ๋งํฌ์ด ๊ฐ์ด 1 ์ด์์ด ๋ ๋๊น์ง ํธ์ถ์๋ฅผ ๋๊ธฐ์ํจ๋ค. ๋ค์์ ์ฐ๋ ๋๋ค์ดsem_wait()์ ํธ์ถํ ์ ์๊ธฐ ๋๋ฌธ์, ๋๊ธฐํ์๋ ๋ค์์ ์ฐ๋ ๋๊ฐ ์กด์ฌํ ์ ์๋ค. ๋๊ธฐํ๋ ๋ฒ์๋ ํ์ ๊ณผ ์ฌ์ฐ๊ธฐ ๋ ๊ฐ์ง๊ฐ ์๋ค๋ ๊ฒ์ ๊ธฐ์ตํ์.sem_post()ํจ์๋ ๋๊ธฐํ์ง ์๋๋ค. ์ธ๋งํฌ์ด ๊ฐ์ ์ฆ๊ฐ์ํค๊ณ ๋๊ธฐ ์ค์ธ ์ฐ๋ ๋ ์ค ํ๋๋ฅผ ๊นจ์ด๋ค.- ์ธ๋งํฌ์ด๊ฐ ์์๋ผ๋ฉด ๊ทธ ๊ฐ์ ํ์ฌ ๋๊ธฐ ์ค์ธ ์ฐ๋ ๋์ ๊ฐ์์ ๊ฐ๋ค.
์ด ๋ ๊ฐ์ ํจ์๋ atomicํ๊ฒ ์คํ๋๋ค๊ณ ๊ฐ์ ํ๋ค.
2. ์ด์ง ์ธ๋งํฌ์ด (๋ฝ)
์ฐ๋ฆฌ๊ฐ ์ฒ์์ผ๋ก ์ธ๋งํฌ์ด๋ฅผ ์ ์ฉํ ๊ณณ์ โ๋ฝโ์ด๋ค.
sem_t m;
sem_init(&m, 0, X); // X๋ก ์ธ๋งํฌ์ด ์ด๊ธฐํํ๊ธฐ.
sem_wait(&m);
// ์๊ณ ์์ญ
sem_post(&m);
X๋ ์ด๋ค ๊ฐ์ด ๋์ด์ผ ํ ๊น? ์กฐ๊ธ๋ง ์๊ฐํด๋ด๋ 1์ด ๋์ด์ผ ํ๋ค๋ ์ฌ์ค์ ์ ์ ์๋ค.
์ฐ๋ ๋๊ฐ 2๊ฐ๋ผ๊ณ ๊ฐ์ ํด๋ณด์. ์ฒซ ๋ฒ์งธ ์ฐ๋ ๋๊ฐ ์ธ๋งํฌ์ด ๊ฐ์ 1 ๊ฐ์์์ผ 0์ผ๋ก ๋ง๋ ๋ค. ์ธ๋งํฌ์ด์ ๊ฐ์ด ์์๊ฐ ์๋๋ฏ๋ก ๋ฆฌํดํ๊ณ ์งํํ๋ค. ์ฒซ ๋ฒ์งธ ์ฐ๋ ๋๊ฐ ์๊ณ ์์ญ์ ์์ ๋ ๋ ๋ฒ์งธ ์ฐ๋ ๋๊ฐ sem_wait()์ ํธ์ถํ์ฌ ์๊ณ ์์ญ ์ง์์ ์๋ํ๋ค๋ฉด ์ด๋ป๊ฒ ๋ ๊น?
์ด ๊ฒฝ์ฐ ๋ ๋ฒ์งธ ์ฐ๋ ๋๊ฐ ์ธ๋งํฌ์ด ๊ฐ์ -1๋ก ๊ฐ์์ํค๊ณ , ๋๊ธฐ์ ๋ค์ด๊ฐ๋ค. ์ฒซ ๋ฒ์งธ ์ฐ๋ ๋๊ฐ ๋ค์ ์คํ๋๋ฉด sem_post()๋ฅผ ํธ์ถํ๊ณ ์ธ๋งํฌ์ด ๊ฐ์ 0์ผ๋ก ์ฆ๊ฐ์ํค๊ณ , ์ ์๋ ๋ ๋ฒ์งธ ์ฐ๋ ๋๋ฅผ ๊นจ์ด๋ค. ๊ทธ๋ฌ๋ฉด ๋ ๋ฒ์งธ ์ฐ๋ ๋๊ฐ ๋ฝ์ ํ๋ํ ์ ์๋ค.
๋ฝ์ ๋ ๊ฐ์ ์ํ (์ฌ์ฉ ๊ฐ๋ฅ, ์ฌ์ฉ ์ค) ๋ง ์กด์ฌํ๋ฏ๋ก ์ด์ง ์ธ๋งํฌ์ด (binary semaphore) ๋ผ๊ณ ๋ ๋ถ๋ฆฐ๋ค.
3. ์ปจ๋์ ๋ณ์๋ก์์ ์ธ๋งํฌ์ด
์ด๋ค ์กฐ๊ฑด์ด ์ฐธ์ด ๋๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ๊ธฐ ์ํด ํ์ฌ ์ฐ๋ ๋๋ฅผ ๋ฉ์ถ ๋์๋ ์ธ๋งํฌ์ด๋ ์ ์ฉํ๊ฒ ์ฌ์ฉ๋๋ค.
sem_t s;
void *child(void *arg) {
printf(โchild\n โ);
sem_post(&s); // ์๊ทธ๋ ์ ๋ฌ: ๋์ ๋
return NULL;
}
int main(int argc, char *argv[]) {
sem_init(&s, 0, X); // X์ ๊ฐ์ ๋ฌด์์ด ๋์ด์ผ ํ ๊น?
printf(โparent: begin\n โ);
pthread_t c;
Pthread_create(c, NULL, child, NULL);
sem_wait(&s); // ์์์ ์ฌ๊ธฐ์ ๋๊ธฐ
printf(โparent: end\n โ);
return 0;
}
๋ค์๊ณผ ๊ฐ์ ์คํ ๊ฒฐ๊ณผ๋ฅผ ์ป๊ณ ์ ํ๋ค.
parent: begin
child
parent: end
์ธ๋งํฌ์ด๋ฅผ ์ด์ฉํ์ฌ ์ด๋ป๊ฒ ์ด ํจ๊ณผ๋ฅผ ๋ง๋ค ์ ์์๊น? ๋ต์ ์์ธ๋ก ๊ฐ๋จํ๋ค. ์ฝ๋์์ ๋ณผ ์ ์๋ฏ์ด, ๋ถ๋ชจ ํ๋ก์ธ์ค๋ ์์ ํ๋ก์ธ์ค ์์ฑ ํ sem_wait()๋ฅผ ํธ์ถํ์ฌ ์์์ ์ข
๋ฃ๋ฅผ ๋๊ธฐํ๋ค. ์์์ sem_post()๋ฅผ ํธ์ถํ์ฌ ์ข
๋ฃ๋์์์ ์๋ฆฐ๋ค.
์ค์ํ ์ง๋ฌธ์ด ์๋ค. ์ธ๋งํฌ์ด ๊ฐ์ ๋ฌด์์ผ๋ก ์ด๊ธฐํํ ๊น?
์ ๋ต์ 0์ด๋ค.
๋ค์๊ณผ ๊ฐ์ ๋ ๊ฐ์ง ๊ฒฝ์ฐ๋ฅผ ํตํด ๊ทธ ์ด์ ๋ฅผ ์์๋ณด์.
-
์์ ํ๋ก์ธ์ค ์์ฑ ํ, ์์ง ์์ ํ๋ก์ธ์ค๊ฐ ์คํ์ ์์ํ์ง ์์ ๊ฒฝ์ฐ๋ค (์ค๋น ํ์๋ง ๋ค์ด ์๊ณ ์คํ ์ค์ด ์๋๋ค). ์ด ๊ฒฝ์ฐ ์์์ด
sem_post()๋ฅผ ํธ์ถํ๊ธฐ ์ ์ ๋ถ๋ชจ๊ฐsem_wait()๋ฅผ ํธ์ถํ ๊ฒ์ด๋ค. ๋ถ๋ชจ ํ๋ก์ธ์ค๋ ์์์ด ์คํ๋ ๋๊น์ง ๋๊ธฐํด์ผ ํ๋ค. ์ด๋ฅผ ์ํด์๋wait()ํธ์ถ ์ ์ ์ธ๋งํฌ์ด ๊ฐ์ด 0๋ณด๋ค ๊ฐ๊ฑฐ๋ ์์์ผ ํ๋ค. ๋๋ฌธ์ 0์ด ์ด๊ธฐ๊ฐ์ด ๋์ด์ผ ํ๋ค. ๋ถ๋ชจ๊ฐ ์คํ๋๋ฉด ์ธ๋งํฌ์ด ๊ฐ์ ๊ฐ์์ํค๊ณ (-1๋ก) ๋๊ธฐํ๋ค. ์์์ด ์คํ๋์์ ๋sem_post()๋ฅผ ํธ์ถํ์ฌ ์ธ๋งํฌ์ด์ ๊ฐ์ 0์ผ๋ก ์ฆ๊ฐ์ํจ ํ ๋ถ๋ชจ๋ฅผ ๊นจ์ด๋ค. ๊ทธ๋ฌ๋ฉด ๋ถ๋ชจ๋sem_wait()์์ ๋ฆฌํด์ ํ์ฌ ํ๋ก๊ทธ๋จ์ ์ข ๋ฃ์ํจ๋ค. -
๋ถ๋ชจ ํ๋ก์ธ์ค๊ฐ
sem_wait()๋ฅผ ํธ์ถํ๊ธฐ ์ ์ ์์ ํ๋ก์ธ์ค์ ์คํ์ด ์ข ๋ฃ๋ ๊ฒฝ์ฐ์ด๋ค. ์ด ๊ฒฝ์ฐ, ์์์ด ๋จผ์ sem_post()๋ฅผ ํธ์ถํ์ฌ ์ธ๋งํฌ์ด์ ๊ฐ์ 0์์ 1๋ก ์ฆ๊ฐ์ํจ๋ค. ๋ถ๋ชจ๊ฐ ์คํํ ์ ์๋ ์ํฉ์ด ๋๋ฉดsem_wait()๋ฅผ ํธ์ถํ๋ค. ์ธ๋งํฌ์ด ๊ฐ์ด 1์ธ ๊ฒ์ ๋ฐ๊ฒฌํ ๊ฒ์ด๋ค. ๋ถ๋ชจ๋ ์ธ๋งํฌ์ด ๊ฐ์ 0์ผ๋ก ๊ฐ์์ํค๊ณsem_wait()์์ ๋๊ธฐ ์์ด ๋ฆฌํดํ๋ค. ์ด ๋ฐฉ๋ฒ ์ญ์ ์๋ํ ๊ฒฐ๊ณผ๋ฅผ ๋ง๋ค์ด๋ธ๋ค.
4. ์์ฐ์/์๋น์ (์ ํ ๋ฒํผ) ๋ฌธ์
์ด ๋ฌธ์ ๋ ์ด์ ์ฅ OSTEP 30 Condition Variables์์ ์์ธํ ์ค๋ช
ํ๋ค. ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด empty์ full์ด๋ผ๋ ๋ ๊ฐ์ ์ธ๋งํฌ์ด๋ฅผ ์ฌ์ฉํ๋ค.
int buffer[MAX];
int fill = 0;
int use = 0;
void put(int value) {
buffer[fill] = value; // f1
fill = (fill + 1) % MAX; // f2
}
int get() {
int tmp = buffer[use]; // g1
use = (use + 1) % MAX; // g2
return tmp;
}
sem_t empty;
sem_t full;
void *producer(void *arg) {
int i;
for (i = 0; i < loops; i++) {
sem_wait(&empty); // P1
put(i); // P2
sem_post(&full); // P3
}
}
void *consumer(void *arg) {
int i, tmp = 0;
while (tmp != โ1) {
sem_wait(&full); // C1
tmp = get(); // C2
sem_post(&empty); // C3
printf(โ%d\n โ, tmp);
}
}
int main(int argc, char *argv[]) {
// . . .
sem_init(&empty, 0, MAX); // empty๋ MAX
sem_init(&full, 0, 0); // full์ 0
// . . .
}
์์ฐ์์ ์๋น์ ์ฐ๋ ๋๊ฐ ๊ฐ ํ๋์ฉ ์๊ณ CPU๋ ํ๋์ธ ์ํฉ์ ๋ํด ์ดํด๋ณด์. ์๋น์๊ฐ ๋จผ์ ์คํํ๋ค๊ณ ๊ฐ์ ํ๋ฉด ์๋น์ ์ฐ๋ ๋๊ฐ ๊ทธ๋ฆผ์์ C1 ๋ผ์ธ์ ๋จผ์ ๋๋ฌํ์ฌ sem_wait(&full)์ ํธ์ถํ๋ค. ๋ณ์full์ ๊ฐ์ 0์ผ๋ก ์ด๊ธฐํ๋์๊ธฐ ๋๋ฌธ์ ํด๋น ๋ช
๋ น์ผ๋ก ์ธํด full์ ๊ฐ์ -1๋ก ๊ฐ์๋๊ณ , ์๋น์๋ ๋๊ธฐํ๋ค. ๋ค๋ฅธ ์ฐ๋ ๋๊ฐ sem_post()๋ฅผ ํธ์ถํด์ full ๋ณ์๊ฐ ์ฆ๊ฐํ๊ธฐ๋ฅผ ๊ธฐ๋ค๋ ค์ผ ํ๋ค.
๊ทธ๋ฐ ์ดํ์ ์์ฐ์ ์ฐ๋ ๋๊ฐ ์คํํ์ฌ P1 ๋ผ์ธ์์ sem_wait(&empty) ๋ฃจํด์ ํธ์ถํ๋ค. empty ๋ณ์๊ฐ MAX (์ด ๊ฒฝ์ฐ์๋ 1)๋ก ์ค์ ๋์๊ธฐ ๋๋ฌธ์ ์๋น์์ ๋ค๋ฅด๊ฒ ์์ฐ์๋ ๋ค์ ๋ฌธ์ฅ์ ๊ณ์ ์คํํ๋ค. empty ๋ณ์๋ ๊ฐ์ํ์ฌ 0์ด ๋๊ณ ์์ฐ์๊ฐ ๋ฐ์ดํฐ ๊ฐ์ ๋ฒํผ์ ์ฒซ ๋ฒ์งธ ๊ณต๊ฐ์ ๋ฃ๋๋ค (P2 ๋ผ์ธ). ๊ทธ๋ฐ ํ์ ์์ฐ์๋ P3 ๋ผ์ธ์ sem_post(&full)๋ฅผ ํธ์ถํ์ฌ full ์ธ๋งํฌ์ด์ ๊ฐ์ -1์์ 0์ผ๋ก ๋ณ๊ฒฝํ๊ณ ์๋น์ ์ฐ๋ ๋๋ฅผ ๊นจ์ด๋ค (๋๊ธฐ ์ํ์์ ์ค๋น ์ํ๋ก ๋ฐ๋๋ค).
๋ง์ฝ MAX ๊ฐ์ด 1๋ณด๋ค ํฌ๊ณ ์์ฐ์์ ์๋น์ ์ฐ๋ ๋๋ค์ด ์ฌ๋ฌ ๊ฐ ์๋ค๋ฉด? ๊ฒฝ์ ์กฐ๊ฑด์ด ๋ฐ์ํ ๊ฒ์ด๋ค. put(), get()์์ ๊ฒฝ์ ์กฐ๊ฑด์ด ๋ฐ์ํ๋ค.
๋ ๊ฐ์ ์์ฐ์ Pa์ Pb๊ฐ ์๋๋ฐ, ๋ ์ฐ๋ ๋๊ฐ put() ์ ๊ฑฐ์ ๋์์ ํธ์ถํ์๋ค๊ณ ํด ๋ณด์. Pa๊ฐ ๋จผ์ ์คํ๋์ด์ ๋ฒํผ์ ์ฒซ ๊ณต๊ฐ์ ๊ฐ์ ๋ฃ๊ธฐ ์์ํ๋ค (f1 ๋ผ์ธ์์ fill = 0์ด๋ค). Pa ์ฐ๋ ๋๊ฐ fill ์นด์ดํฐ ๋ณ์๋ฅผ 1๋ก ๋ณ๊ฒฝํ๊ธฐ ์ ์ ์ธํฐ๋ฝํธ๊ฐ ๊ฑธ๋ ธ๋ค. ์์ฐ์ Pb๊ฐ ์คํ๋๊ณ f1 ๋ผ์ธ์์ ๋ง์ฐฌ๊ฐ์ง๋ก ๋ฒํผ์ ์ฒซ ๋ฒ์งธ ๊ณต๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์
ํ๋ค. Pa๊ฐ ๊ธฐ๋กํ ์ด์ ์ ๊ฐ์ ์๋ก์ด ๊ฐ์ผ๋ก ๋์ฒด๋๋ค.
์ํธ ๋ฐฐ์ ์ถ๊ฐ
๋ฒํผ๋ฅผ ์ฑ์ฐ๊ณ ๋ฒํผ์ ๋ํ ์ธ๋ฑ์ค๋ฅผ ์ฆ๊ฐํ๋ ๋์์ ์๊ณ ์์ญ์ด๊ธฐ ๋๋ฌธ์ ์ ์คํ๊ฒ ์ฒ๋ฆฌํด์ผ ํ๋ค. ์ง๊ธ๊น์ง ๋ฐฐ์ด ์ด์ง ์ธ๋งํฌ์ด์ ๋ช ๊ฐ์ ๋ฝ์ ์ถ๊ฐํ์ฌ ํด๊ฒฐํด๋ณด์.
sem_t empty;
sem_t full;
sem_t mutex;
void *producer(void *arg) {
int i;
for (i = 0; i < loops; i++) {
sem_wait(&mutex); // P0
sem_wait(&empty); // P1
put(i); // P2
sem_post(&full); // P3
sem_post(&mutex); // P4
}
}
void *consumer(void *arg) {
int i, tmp = 0;
while (tmp != โ1) {
sem_wait(&mutex); // C0
sem_wait(&full); // C1
tmp = get(); // C2
sem_post(&empty); // C3
sem_post(&mutex); // C4
printf(โ%d\n โ, tmp);
}
}
int main(int argc, char *argv[]) {
// . . .
sem_init(&empty, 0, MAX); // empty๋ MAX
sem_init(&full, 0, 0); // full์ 0
sem_init(&mutex,0 ,1); // lock์ 1๋ก ์ด๊ธฐํ
// . . .
}
์ด๋ ๊ฒ ํ๋ฉด ๊ต์ฐฉ ์ํ๊ฐ ๋ฐ์ํ๋ค.
์์ฐ์์ ์๋น์ ์ฐ๋ ๋๊ฐ ๊ฐ ํ๋์ฉ ์๋ค๊ณ ํ์. ์๋น์๊ฐ ๋จผ์ ์คํ์ด ๋์๋ค. mutex(c0 ๋ผ์ธ)๋ฅผ ํ๋ํ๊ณ full ๋ณ์์ ๋ํ์ฌ sem_wait()(c1 ๋ผ์ธ)๋ฅผ ํธ์ถํ๋ค. ์์ง ๋ฐ์ดํฐ๊ฐ ์๊ธฐ ๋๋ฌธ์ ์๋น์๋ ๋๊ธฐํด์ผ ํ๊ณ CPU๋ฅผ ์๋ณดํด์ผ ํ๋ค.
์ฌ๊ธฐ์ ์ค์ํ ๊ฒ์ ์๋น์๊ฐ ์์ง๋ ๋ฝ์ ํ๋ํ๊ณ ์๋ค๋ ๊ฒ์ด๋ค. ์์ฐ์๊ฐ ์คํ๋๋ค. ์คํ์ด ๊ฐ๋ฅํ๋ฉด ๋ฐ์ดํฐ๋ฅผ ์์ฑํ๊ณ ์๋น์ ์ฐ๋ ๋๋ฅผ ๊นจ์ธ ๊ฒ์ด๋ค. ๋ถํํ๊ฒ๋ ์ด ์ฐ๋ ๋๋ ๋จผ์ mutex ์ธ๋งํฌ์ด์ ๋ํด์ sem_wait()๋ฅผ ์คํํ๋ค(p0 ๋ผ์ธ). ์ด๋ฏธ ๋ฝ์ ์๋น์๊ฐ ํ๋ํ ์ํ์ด๊ธฐ ๋๋ฌธ์ ์์ฐ์ ์ญ์ ๋๊ธฐ์ ๋ค์ด๊ฐ๋ค.
์ํ ๊ณ ๋ฆฌ๊ฐ ์๊ฒผ๋ค. ์๋น์๋ mutex๋ฅผ ๊ฐ๊ณ ์์ผ๋ฉด์ ๋ค๋ฅธ full ์๊ทธ๋์ ๋ฐ์์ํค๊ธฐ๋ฅผ ๋๊ธฐํ๊ณ ์๋ค. full ์๊ทธ๋์ ๋ฐ์์์ผ์ผ ํ๋ ์์ฐ์๋ mutex์์ ๋๊ธฐ์ค์ด๋ค. ์์ฐ์์ ์๋น์๊ฐ ์๋ก๋ฅผ ๊ธฐ๋ค๋ฆฐ๋ค. ์ ํ์ ์ธ ๊ต์ฐฉ ์ํ์ด๋ค.
์ ๋๋ก ๋ ํด๋ฒ
์ด๋ ๊ฒ ๋ฝ์ ๋ฒ์๋ฅผ ์ค์ฌ์ผ ํ๋ค. ๋ฎคํ ์ค๊ฐ ์๊ณ ์์ญ๋ง ๊ฐ์ธ๋๋ก ๋ฐ๊ฟ๋ณด์.
sem_t empty;
sem_t full;
sem_t mutex;
void *producer(void *arg) {
int i;
for (i = 0; i < loops; i++) {
sem_wait(&empty); // p1
sem_wait(&mutex); // p1.5
put(i); // p2
sem_post(&mutex); // p2.5
sem_post(&full); // p3
}
}
void *consumer(void *arg) {
int i;
for (i = 0; i < loops; i++) {
sem_wait(&full); // c1
sem_wait(&mutex); // c1.5
int tmp = get(); // c2
sem_post(&mutex); // c2.5
sem_post(&empty); // c3
printf(โ%d\n โ, tmp);
}
}
int main(int argc, char *argv[]) {
// . . .
sem_init(&empty, 0, MAX);
sem_init(&full, 0, 0);
sem_init(&mutex, 0,1);
// . . .
}
๋ฉํฐ ์ฐ๋ ๋ ํ๋ก๊ทธ๋จ์์ ์ฌ์ฉ ๊ฐ๋ฅํ ์ ํ ๋ฒํผ๋ฅผ ๋ง๋ค์๋ค!
5. Reader-Writer ๋ฝ
์ฝ์ ์ฐ์ฐ์ ๋ฆฌ์คํธ์ ์ํ๋ฅผ ๋ณ๊ฒฝํ๊ณ (์ ํต์ ์ธ ์๊ณ ์์ญ ๋ณดํธ ๋ฐฉ์์ผ๋ก ํด๊ฒฐ ๊ฐ๋ฅํ๋ค), ๊ฒ์์ ์๋ฃ ๊ตฌ์กฐ๋ฅผ ๋จ์ํ ์ฝ๊ธฐ๋ง ํ๋ค. ์ฝ์ ์ฐ์ฐ์ด ์๋ค๋ ๋ณด์ฅ๋ง ๋๋ค๋ฉด ๋ค์์ ๊ฒ์ ์์ ์ ๋์์ ์ํํ ์ ์๋ค. ์ด์ ๊ฐ์ ๊ฒฝ์ฐ๋ฅผ ์ํด ๋ง๋ค์ด์ง ๋ฝ์ด reader-writer ๋ฝ์ด๋ค
typedef struct _rwlock_t {
sem_t lock; // ์ด์ง ์ธ๋งํฌ์ด (๊ธฐ๋ณธ ๋ฝ)
sem_t writelock; // ํ๋์ ์ฐ๊ธฐ ๋๋ ๋ค์์ ์ฝ๊ธฐ ๋ฝ์ ์ํ ๋ฝ
int readers; // ์๊ณ ์์ญ ๋ด์ ์ฝ๊ธฐ๋ฅผ ์ํ์ค์ธ reader์ ์
} rwlock_t;
void rwlock_init(rwlock_t *rw) {
rwโ>readers = 0;
sem_init(&rwโ>lock, 0, 1);
sem_init(&rwโ>writelock, 0, 1);
}
void rwlock_acquire_readlock(rwlock_t *rw) {
sem_wait(&rwโ>lock); // readers๋ฅผ ๋ณ๊ฒฝํ๊ธฐ ์ํด ์ด์ง ์ธ๋งํฌ์ด ์ฌ์ฉ
rwโ>readers++;
if (rwโ>readers == 1)
sem_wait(&rwโ>writelock); // ์ฝ๊ธฐ์ฉ ๋ฝ์ด writelock ํ๋
sem_post(&rwโ>lock);
}
void rwlock_release_readlock(rwlock_t *rw) {
sem_wait(&rwโ>lock);
rwโ>readersโโ;
if (rwโ>readers == 0)
sem_post(&rwโ>writelock); // ๋ง์ง๋ง์ผ๋ก ์ฝ๊ธฐ์ฉ ๋ฝ์ด writelock ํด์
sem_post(&rwโ>lock);
}
void rwlock_acquire_writelock(rwlock_t *rw) {
sem_wait(&rwโ>writelock);
}
void rwlock_release_writelock(rwlock_t *rw) {
sem_post(&rwโ>writelock);
}
์ด ์ฝ๋๋ ๊ฐ๋จํ๋ค. ์๋ฃ ๊ตฌ์กฐ๋ฅผ โ๊ฐฑ์ โํ๋ ค๋ฉด ์๋ก์ด ๋๊ธฐํ ์ฐ์ฐ ์์ ์ฌ์ฉํ๋ค. ๋ฝ์ ํ๋ํ๊ธฐ ์ํด์๋ rwlock_acquire_writelock()์ ์ฌ์ฉํ๊ณ ํด์ ํ๊ธฐ ์ํด์ rwlock_release_writelock()์ ์ฌ์ฉํ๋ค. ๋ด๋ถ์ ์ผ๋ก๋ writelock ์ธ๋งํฌ์ด๋ฅผ ์ฌ์ฉํ์ฌ ํ๋์ ์ฐ๊ธฐ ์ฐ๋ ๋๋ง์ด ๋ฝ์ ํ๋ํ ์ ์๋๋ก ํ์ฌ, ์๊ณ ์์ญ ์ง์ ํ์ ์๋ฃ ๊ตฌ์กฐ๋ฅผ ๊ฐฑ์ ํ๋ค.
์ฝ๊ธฐ ๋ฝ์ ํ๋์ ์ฝ๊ธฐ ์ฐ๋ ๋(reader)๊ฐ ๋จผ์ ๋ฝ์ ํ๋ํ๊ณ ์ฝ๊ธฐ ์ค์ธ ์ฐ๋ ๋์ ์๋ฅผ ํํํ๋ reader ๋ณ์๋ฅผ ์ฆ๊ฐ์ํจ๋ค. ์ฒซ ๋ฒ์งธ ์ฝ๊ธฐ ์ฐ๋ ๋๊ฐ ์ฝ๊ธฐ ๋ฝ์ ํ๋ํ ๋ ์ค์ํ ๊ณผ์ ์ด ์๋ค. ์ฝ๊ธฐ ๋ฝ์ ํ๋์ writelock ์ธ๋งํฌ์ด์ ๋ํด sem_wait()์ ํธ์ถํ์ฌ ์ฐ๊ธฐ ๋ฝ์ ํจ๊ป ํ๋ํ๋ค. ํ๋ํ ์ฐ๊ธฐ ๋ฝ์ ์ฝ๊ธฐ ๋ฝ์ ํด์ ํ ๋ sem_post()๋ก ๋ค์ ํด์ ํ๋ค.
์ด ๊ณผ์ ์ ํตํด์ ์ฝ๊ธฐ ๋ฝ์ ํ๋ํ๊ณ ๋ ํ, ๋ค๋ฅธ ์ฝ๊ธฐ ์ฐ๋ ๋๋ค์ด ์ฝ๊ธฐ ๋ฝ์ ํ๋ํ ์ ์๋๋ก ํ๋ค. ๋ค๋ง, ์ฐ๊ธฐ ๋ฝ์ ํ๋ํ๋ ค๋ ์ฐ๊ธฐ ์ฐ๋ ๋ (writer)๋ค์ ๋ชจ๋ ์ฝ๊ธฐ ์ฐ๋ ๋๊ฐ ๋๋ ๋๊น์ง ๋๊ธฐํ์ฌ์ผ ํ๋ค. ์๊ณ ์์ญ์ ๋น ์ ธ๋์ค๋ ๋ง์ง๋ง ์ฝ๊ธฐ ์ฐ๋ ๋๊ฐ โwritelockโ์ ๋ํ sem_post()๋ฅผ ํธ์ถํ์ฌ ๋๊ธฐ ์ค์ธ ์ฐ๊ธฐ ์ฐ๋ ๋๊ฐ ๋ฝ์ ํ๋ํ ์ ์๋๋ก ํ๋ค.
์ด ๋ฐฉ์์ ๋ช๊ฐ์ง ๋จ์ ์ด ์กด์ฌํ๋ค.
์ฐ๊ธฐ ์ฐ๋ ๋์๊ฒ ๋ถ๋ฆฌํ ๋ฐฉ์์ด๋ค. ์ฐ๊ธฐ ์ฐ๋ ๋์๊ฒ ๊ธฐ์ ํ์์ด ๋ฐ์ํ ์ ์๋ค. ์ฐ๊ธฐ ์ฐ์ ์ ์ฑ ๋ฑ์ ์ฌ์ฉํด์ ๊ธฐ์ ํ์์ ์ค์ผ ์ ์๋ค.
typedef struct _rwlock_t {
sem_t lock; // ๊ธฐ๋ณธ ๋ฝ
sem_t writelock; // ์ฐ๊ธฐ ๋๋ ์ฝ๊ธฐ ๋ฝ
sem_t writer_sem; // ์ฐ๊ธฐ ์์
์ ์ํ ์ธ๋งํฌ์ด
int readers; // ์ฝ๊ธฐ ์์
์
int waiting_writers; // ๋๊ธฐ ์ค์ธ ์ฐ๊ธฐ ์์
์
} rwlock_t;
void rwlock_init(rwlock_t *rw) {
rw->readers = 0;
rw->waiting_writers = 0;
sem_init(&rw->lock, 0, 1);
sem_init(&rw->writelock, 0, 1);
sem_init(&rw->writer_sem, 0, 1);
}
void rwlock_acquire_readlock(rwlock_t *rw) {
sem_wait(&rw->writer_sem); // ์ฐ๊ธฐ ์์
์ด ๋๊ธฐ ์ค์ผ ๊ฒฝ์ฐ ์ฐจ๋จ
sem_wait(&rw->lock);
rw->readers++;
if (rw->readers == 1) {
sem_wait(&rw->writelock);
}
sem_post(&rw->lock);
sem_post(&rw->writer_sem);
}
void rwlock_release_readlock(rwlock_t *rw) {
sem_wait(&rw->lock);
rw->readers--;
if (rw->readers == 0) {
sem_post(&rw->writelock);
}
sem_post(&rw->lock);
}
void rwlock_acquire_writelock(rwlock_t *rw) {
sem_wait(&rw->writer_sem);
rw->waiting_writers++;
sem_post(&rw->writer_sem);
sem_wait(&rw->writelock);
sem_wait(&rw->writer_sem);
rw->waiting_writers--;
sem_post(&rw->writer_sem);
}
void rwlock_release_writelock(rwlock_t *rw) {
sem_post(&rw->writelock);
}
์ด๋ ๊ฒ ๊ตฌํํ๋ฉด, ์ฐ๊ธฐ ์์
์ด ๋๊ธฐ ์ค์ผ ๋ ์๋ก์ด ์ฝ๊ธฐ ์์
์ด ๋ฝ์ ํ๋ํ์ง ๋ชปํ๊ฒ ๋๋ค. ์ด๋ writer_sem ์ธ๋งํฌ์ด๋ฅผ ํตํด ๊ด๋ฆฌ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ์ฐ๊ธฐ ์์
์ด ๋๊ธฐ ์ค์ผ ๋ ์ฝ๊ธฐ ์์
์ด ์์ด๋ ๊ฒ์ ๋ฐฉ์งํ ์ ์์ผ๋ฏ๋ก ์ฐ๊ธฐ ์์
์ ๊ธฐ์ ํ์์ ์ค์ผ ์ ์๋ค.
6. ์์ฌํ๋ ์ฒ ํ์

๋ค์ฏ ๋ช ์ โ์ฒ ํ์โ๊ฐ ์ํ ์ฃผ์๋ฅผ ๋๋ฌ์์๋ค. ์ด ๋ค์ฏ ๊ฐ์ ํฌํฌ๊ฐ ์ฒ ํ์์ ์ฒ ํ์ ์ฌ์ด์ ํ๋์ฉ ๋์ฌ ์๋ค. ์ฒ ํ์๋ ์์ฌํ๋ ๋๊ฐ ์๊ณ ์๊ฐํ๋ ๋๊ฐ ์๋ค. ์๊ฐ ์ค์ผ ๋๋ ํฌํฌ๊ฐ ํ์ ์๋ค. ์์ ์ ์ผ์ชฝ๊ณผ ์ค๋ฅธ์ชฝ์ ์๋ ํฌํฌ๋ฅผ ๋ค์ด์ผ ์์ฌ๋ฅผ ํ ์ ์๋ค. ์ด ํฌํฌ๋ฅผ ์ก๊ธฐ ์ํ ๊ฒฝ์๊ณผ ๊ทธ์ ๋ฐ๋ฅธ ๋๊ธฐํ ๋ฌธ์ ๊ฐ ๋ณํ ํ๋ก๊ทธ๋๋ฐ์์ ๋ค๋ฃจ๋ ค๋ ์์ฌํ๋ ์ฒ ํ์ ๋ฌธ์ ์ด๋ค.
while (1) {
think();
getforks();
eat();
putforks();
}
์ฃผ์ ์์ ์ getfork()์ putfork()์ ๋ฃจํด์ ์์ฑํ๋ ๊ต์ฐฉ ์ํ์ ๋ฐ์์ ๋ฐฉ์งํด์ผ ํ๊ณ , ์ด๋ค ์ฒ ํ์๋ ๋ชป ๋จน์ด์ ๊ตถ์ฃผ๋ฆฌ๋ฉด ์๋๋ฉฐ ๋ณํ์ฑ์ด ๋์์ผ ํ๋ค. ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํด๋ณด์.
int left(int p) { return p; }
int right(int p) { return (p + 1) % 5; }
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์ ์ธ๋งํฌ์ด๊ฐ ํ์ํ๋ค. ๊ฐ ํฌํฌ๋ง๋ค ํ ๊ฐ์ฉ ์ด ๋ค์ฏ ๊ฐ๊ฐ ์๊ณ sem_t fork[5]๋ก ์ ์ํ๋ค.
void getforks() {
sem_wait(forks[left(p)]);
sem_wait(forks[right(p)]);
}
void putforks() {
sem_post(forks[left(p)]);
sem_post(forks[right(p)]);
}
ํฌํฌ๊ฐ ํ์ํ ๋ ํ๋์ ๋ฝ์ ํ๋ํ๋ค. ๊ทธ๋ฆฌ๊ณ ์์ฌ๊ฐ ๋๋๋ฉด ์์๋๋ก ๋๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ๊ต์ฐฉ ์ํ๊ฐ ๋ฐ์ํ๋ค. ๊ฐ ์ฒ ํ์๊ฐ ๋์์ ์๊ธฐ ์ผ์ชฝ์ ์๋ ํฌํฌ๋ฅผ ์ง์ผ๋ฉด ํ์ ๊ธฐ๋ค๋ ค์ผ ํ๋ค.
ํด๋ต: ์์กด์ฑ ์ ๊ฑฐ
๊ฐ๋จํ ํด๋ฒ ์ค ํ๋๋ ์ต์ํ ํ๋์ ์ฒ ํ์๊ฐ ๋ค๋ฅธ ์์๋ก ํฌํฌ๋ฅผ ์ง๋๋ก ํ๋ ๊ฒ์ด๋ค.
void getforks() {
if (p == 4) {
sem_wait(forks[right(p)]); // ์ค๋ฅธ์ชฝ ํฌํฌ ๋จผ์ ์ง๋๋ก
sem_wait(forks[left(p)]);
} else {
sem_wait(forks[left(p)]);
sem_wait(forks[right(p)]);
}
}
์ด๋ ๊ฒ ํด์ ํํ ๋๊ธฐ ์ํ๋ฅผ ๋์ ์ ์๋ค.
7. ์ฐ๋ ๋ ์ฐ๋กํ๋ง
๋๋ฌด ๋ง์ ์ฐ๋ ๋๊ฐ ๋์์ ์์ ์ ์ํํ์ง ์๋๋ก, ์ธ๋งํฌ์ด๋ฅผ ์ฌ์ฉํ์ฌ ๋์์ ์คํ๋๋ ์ฐ๋ ๋ ์๋ฅผ ์ ํํ๋ค.
๋ฌธ์ ์ํฉ ์์
์๋ฅผ ๋ค์ด, ์๋ฐฑ ๊ฐ์ ์ฐ๋ ๋๋ฅผ ๋ง๋ค์ด ๋ณ๋ ฌ ์์ ์ ์ํํ๋ค๊ณ ๊ฐ์ ํ์. ์ฝ๋์ ํน์ ๋ถ๋ถ์์๋ ๊ฐ ์ฐ๋ ๋๊ฐ ๋ง์ ์์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ ์ ํด ๊ณ์ฐ์ ์ํํ๋๋ฐ, ์ด ๋ถ๋ถ์ โ๋ฉ๋ชจ๋ฆฌ ์ง์ค ๊ตฌ์ญโ์ด๋ผ๊ณ ์นญํ์. ๋ง์ฝ ๋ชจ๋ ์ฐ๋ ๋๊ฐ ๋์์ ์ด ๋ฉ๋ชจ๋ฆฌ ์ง์ค ๊ตฌ์ญ์ ์ง์ ํ๊ฒ ๋๋ฉด, ๋ฌผ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ์ ์ด๋์ ์ด๊ณผํ๋ ๋ฉ๋ชจ๋ฆฌ ํ ๋น ์์ฒญ์ด ๋ฐ์ํ ๊ฒ์ด๋ค. ์ด๋ก ์ธํด ์์คํ ์ ์ค๋์ฑ(thrashing) ์ ์์ํ์ฌ, ๋์คํฌ์์ ํ์ด์ง ๊ตํ์ด ๋น๋ฒํ๊ฒ ์ผ์ด๋๊ณ ์ ์ฒด ๊ณ์ฐ ์ฑ๋ฅ์ด ๊ธ๊ฒฉํ ์ ํ๋ ๊ฒ์ด๋ค.
์ธ๋งํฌ์ด๋ฅผ ์ด์ฉํ ํด๊ฒฐ ๋ฐฉ์
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๊ฐ๋จํ ๋ฐฉ๋ฒ์ ์ธ๋งํฌ์ด๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด๋ค. ์ธ๋งํฌ์ด์ ์ด๊ธฐ ๊ฐ์ ๋ฉ๋ชจ๋ฆฌ ์ง์ค ๊ตฌ์ญ์ ๋์์ ์ง์
ํ ์ ์๋ ์ต๋ ์ฐ๋ ๋ ์๋ก ์ค์ ํ๋ค. ๊ทธ ๋ค์, ์ด ๊ตฌ์ญ์ sem_wait()์ sem_post() ํจ์ ํธ์ถ์ ๊ฐ์ธ์ ์ธ๋งํฌ์ด๋ฅผ ์ ์ฉํ๋ค. ์ด๋ ๊ฒ ํ๋ฉด, ์ธ๋งํฌ์ด๊ฐ ์์ฐ์ค๋ฝ๊ฒ ๋ฉ๋ชจ๋ฆฌ ์ง์ค ๊ตฌ์ญ์์ ๋์์ ์คํ๋ ์ ์๋ ์ฐ๋ ๋ ์๋ฅผ ์ ํํ๊ฒ ๋๋ค.
8. ์ธ๋งํฌ์ด ๊ตฌํ
์ ์์ค ๋๊ธฐํ ๊ธฐ๋ฒ์ธ ๋ฝ๊ณผ ์ปจ๋์ ๋ณ์๋ฅผ ์ฌ์ฉํ์ฌ ์ฐ๋ฆฌ๋ง์ ์ธ๋งํฌ์ด๋ฅผ ๋ง๋ค์ด ๋ณด์. (Zemaphore)
typedef struct __Zem_t {
int value;
pthread_cond_t cond;
pthread_mutex_t lock;
} Zem_t;
// ์ค์ง ํ๋์ ์ฐ๋ ๋๋ง ์ด ๋ฌธ์ฅ์ ํธ์ถํ ์ ์๋ค.
void Zem_init(Zem_t *s, int value) {
sโ>value = value;
Cond_init(&sโ>cond);
Mutex_init(&sโ>lock);
}
void Zem_wait(Zem_t *s) {
Mutex_lock(&sโ>lock);
while (sโ>value <= 0)
Cond_wait(&sโ>cond, &sโ>lock);
sโ>valueโโ;
Mutex_unlock(&sโ>lock);
}
void Zem_post(Zem_t *s) {
Mutex_lock(&sโ>lock);
sโ>value++;
Cond_signal(&sโ>cond);
Mutex_unlock(&sโ>lock);
}
Dijkstra๊ฐ ์ ์ํ ์ธ๋งํฌ์ด์ ์ฌ๊ธฐ์ ์ ์ํ ์ ๋งํฌ์ด ๊ฐ์ ์ค์ํ ์ฐจ์ด ์ค ํ๋๋ ์ธ๋งํฌ์ด์ ์์ ๊ฐ์ด ๋๊ธฐ ์ค์ธ ์ฐ๋ ๋์ ์๋ฅผ ๋ํ๋ธ๋ค๋ ๋ถ๋ถ์ด๋ค. ์ฌ์ค ์ ๋งํฌ์ด์์๋ ์ด ๊ฐ์ด 0 ๋ณด๋ค ์์ ์๊ฐ ์๋ค. ์ด ๋ฐฉ์์ด ๊ตฌํํ๊ธฐ๋ ์ฝ๊ณ ํ์ฌ Linux์ ๊ตฌํ๋ ๋ฐฉ์์ด๊ธฐ๋ ํ๋ค.
์ธ๋งํฌ์ด๋ฅผ ์ฌ์ฉํ์ฌ ๋ฝ๊ณผ ์ปจ๋์ ๋ณ์๋ฅผ ๋ง๋๋ ๊ฒ์ ๋งค์ฐ ๊น๋ค๋ก์ด ๋ฌธ์ ์ด๋ค. ์ธ๋งํฌ์ด๋ก ์ปจ๋์ ๋ณ์ ๊ตฌํ์ ์ฑ๊ณตํ๋ค๋ฉด, ๋น์ ์ ๋ฐ์ด๋ ๊ฐ๋ฐ์์ ์์์ ๊ฐ์ง๊ณ ์๋ ๊ฒ์ด๋ค.