9 min read

OSTEP 31 Semaphores

Table of Contents

๋‹ค์–‘ํ•œ ๋ฒ”์ฃผ์˜ ๋ณ‘ํ–‰์„ฑ ๋ฌธ์ œ ํ•ด๊ฒฐ์„ ์œ„ํ•ด์„œ๋Š” ๋ฝ๊ณผ ์กฐ๊ฑด ๋ณ€์ˆ˜ ๋‘˜ ๋‹ค ํ•„์š”ํ•˜๋‹ค. ์ด๋ฒˆ ์žฅ์—์„œ ๋‹ค๋ฃฐ ์„ธ๋งˆํฌ์–ด๋Š” ๋ฝ๊ณผ ์ปจ๋””์…˜ ๋ณ€์ˆ˜๋กœ ๋ชจ๋‘ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ•ต์‹ฌ ์งˆ๋ฌธ : ์„ธ๋งˆํฌ์–ด๋ฅผ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”๊ฐ€ ๋ฝ๊ณผ ์ปจ๋””์…˜ ๋ณ€์ˆ˜ ๋Œ€์‹ ์— ์„ธ๋งˆํฌ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋ฌด์—‡์ธ๊ฐ€? ์„ธ๋งˆํฌ์–ด์˜ ์ •์˜๋Š” ๋ฌด์—‡์ธ๊ฐ€? ์ด์ง„ ์„ธ๋งˆํฌ์–ด๋Š” ๋ฌด์—‡์ธ๊ฐ€? ๋ฝ๊ณผ ์ปจ๋””์…˜ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์„ธ๋งˆํฌ์–ด๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•œ๊ฐ€? ๊ทธ ๋ฐ˜๋Œ€๋กœ ์„ธ๋งˆํฌ์–ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฝ๊ณผ ์กฐ๊ฑด ๋ณ€์ˆ˜๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•œ๊ฐ€?

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;
}
  1. sem_wait() ํ•จ์ˆ˜๋Š” ์ฆ‰์‹œ ๋ฆฌํ„ดํ•˜๊ฑฐ๋‚˜ (์„ธ๋งˆํฌ์–ด์˜ ๊ฐ’์ด 1 ์ด์ƒ์ด๋ฉด), ์•„๋‹ˆ๋ฉด ํ•ด๋‹น ์„ธ๋งˆํฌ์–ด ๊ฐ’์ด 1 ์ด์ƒ์ด ๋  ๋•Œ๊นŒ์ง€ ํ˜ธ์ถœ์ž๋ฅผ ๋Œ€๊ธฐ์‹œํ‚จ๋‹ค. ๋‹ค์ˆ˜์˜ ์“ฐ๋ ˆ๋“œ๋“ค์ด sem_wait()์„ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ๋Œ€๊ธฐํ์—๋Š” ๋‹ค์ˆ˜์˜ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์กด์žฌํ•  ์ˆ˜ ์žˆ๋‹ค. ๋Œ€๊ธฐํ•˜๋Š” ๋ฒ•์—๋Š” ํšŒ์ „๊ณผ ์žฌ์šฐ๊ธฐ ๋‘ ๊ฐ€์ง€๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๊ธฐ์–ตํ•˜์ž.
  2. sem_post() ํ•จ์ˆ˜๋Š” ๋Œ€๊ธฐํ•˜์ง€ ์•Š๋Š”๋‹ค. ์„ธ๋งˆํฌ์–ด ๊ฐ’์„ ์ฆ๊ฐ€์‹œํ‚ค๊ณ  ๋Œ€๊ธฐ ์ค‘์ธ ์“ฐ๋ ˆ๋“œ ์ค‘ ํ•˜๋‚˜๋ฅผ ๊นจ์šด๋‹ค.
  3. ์„ธ๋งˆํฌ์–ด๊ฐ€ ์Œ์ˆ˜๋ผ๋ฉด ๊ทธ ๊ฐ’์€ ํ˜„์žฌ ๋Œ€๊ธฐ ์ค‘์ธ ์“ฐ๋ ˆ๋“œ์˜ ๊ฐœ์ˆ˜์™€ ๊ฐ™๋‹ค.

์ด ๋‘ ๊ฐœ์˜ ํ•จ์ˆ˜๋Š” 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์ด๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‘ ๊ฐ€์ง€ ๊ฒฝ์šฐ๋ฅผ ํ†ตํ•ด ๊ทธ ์ด์œ ๋ฅผ ์•Œ์•„๋ณด์ž.

  1. ์ž์‹ ํ”„๋กœ์„ธ์Šค ์ƒ์„ฑ ํ›„, ์•„์ง ์ž์‹ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์‹คํ–‰์„ ์‹œ์ž‘ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ๋‹ค (์ค€๋น„ ํ์—๋งŒ ๋“ค์–ด ์žˆ๊ณ  ์‹คํ–‰ ์ค‘์ด ์•„๋‹ˆ๋‹ค). ์ด ๊ฒฝ์šฐ ์ž์‹์ด sem_post()๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์ „์— ๋ถ€๋ชจ๊ฐ€ sem_wait()๋ฅผ ํ˜ธ์ถœํ•  ๊ฒƒ์ด๋‹ค. ๋ถ€๋ชจ ํ”„๋กœ์„ธ์Šค๋Š” ์ž์‹์ด ์‹คํ–‰๋  ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐํ•ด์•ผ ํ•œ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด์„œ๋Š” wait() ํ˜ธ์ถœ ์ „์— ์„ธ๋งˆํฌ์–ด ๊ฐ’์ด 0๋ณด๋‹ค ๊ฐ™๊ฑฐ๋‚˜ ์ž‘์•„์•ผ ํ•œ๋‹ค. ๋•Œ๋ฌธ์— 0์ด ์ดˆ๊ธฐ๊ฐ’์ด ๋˜์–ด์•ผ ํ•œ๋‹ค. ๋ถ€๋ชจ๊ฐ€ ์‹คํ–‰๋˜๋ฉด ์„ธ๋งˆํฌ์–ด ๊ฐ’์„ ๊ฐ์†Œ์‹œํ‚ค๊ณ  (-1๋กœ) ๋Œ€๊ธฐํ•œ๋‹ค. ์ž์‹์ด ์‹คํ–‰๋˜์—ˆ์„ ๋•Œ sem_post()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์„ธ๋งˆํฌ์–ด์˜ ๊ฐ’์„ 0์œผ๋กœ ์ฆ๊ฐ€์‹œํ‚จ ํ›„ ๋ถ€๋ชจ๋ฅผ ๊นจ์šด๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๋ถ€๋ชจ๋Š” sem_wait()์—์„œ ๋ฆฌํ„ด์„ ํ•˜์—ฌ ํ”„๋กœ๊ทธ๋žจ์„ ์ข…๋ฃŒ์‹œํ‚จ๋‹ค.

  2. ๋ถ€๋ชจ ํ”„๋กœ์„ธ์Šค๊ฐ€ 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. ์‹์‚ฌํ•˜๋Š” ์ฒ ํ•™์ž

OSTEP 31 Semaphores-1694985025028.jpeg

๋‹ค์„ฏ ๋ช…์˜ โ€œ์ฒ ํ•™์žโ€๊ฐ€ ์‹ํƒ ์ฃผ์œ„๋ฅผ ๋‘˜๋Ÿฌ์•‰์•˜๋‹ค. ์ด ๋‹ค์„ฏ ๊ฐœ์˜ ํฌํฌ๊ฐ€ ์ฒ ํ•™์ž์™€ ์ฒ ํ•™์ž ์‚ฌ์ด์— ํ•˜๋‚˜์”ฉ ๋†“์—ฌ ์žˆ๋‹ค. ์ฒ ํ•™์ž๋Š” ์‹์‚ฌํ•˜๋Š” ๋•Œ๊ฐ€ ์žˆ๊ณ  ์ƒ๊ฐํ•˜๋Š” ๋•Œ๊ฐ€ ์žˆ๋‹ค. ์ƒ๊ฐ ์ค‘์ผ ๋•Œ๋Š” ํฌํฌ๊ฐ€ ํ•„์š” ์—†๋‹ค. ์ž์‹ ์˜ ์™ผ์ชฝ๊ณผ ์˜ค๋ฅธ์ชฝ์— ์žˆ๋Š” ํฌํฌ๋ฅผ ๋“ค์–ด์•ผ ์‹์‚ฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ํฌํฌ๋ฅผ ์žก๊ธฐ ์œ„ํ•œ ๊ฒฝ์Ÿ๊ณผ ๊ทธ์— ๋”ฐ๋ฅธ ๋™๊ธฐํ™” ๋ฌธ์ œ๊ฐ€ ๋ณ‘ํ–‰ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ ๋‹ค๋ฃจ๋ ค๋Š” ์‹์‚ฌํ•˜๋Š” ์ฒ ํ•™์ž ๋ฌธ์ œ์ด๋‹ค.

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์— ๊ตฌํ˜„๋œ ๋ฐฉ์‹์ด๊ธฐ๋„ ํ•˜๋‹ค.

์„ธ๋งˆํฌ์–ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฝ๊ณผ ์ปจ๋””์…˜ ๋ณ€์ˆ˜๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ ๋งค์šฐ ๊นŒ๋‹ค๋กœ์šด ๋ฌธ์ œ์ด๋‹ค. ์„ธ๋งˆํฌ์–ด๋กœ ์ปจ๋””์…˜ ๋ณ€์ˆ˜ ๊ตฌํ˜„์— ์„ฑ๊ณตํ•œ๋‹ค๋ฉด, ๋‹น์‹ ์€ ๋›ฐ์–ด๋‚œ ๊ฐœ๋ฐœ์ž์˜ ์†Œ์–‘์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.