6 min read

OSTEP 27 Thread API

Table of Contents

์•ž์„œ ์†Œ๊ฐœํ•œ ์“ฐ๋ ˆ๋“œ๋ฅผ ๋‹ค๋ฃจ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž.

1. ์“ฐ๋ ˆ๋“œ ์ƒ์„ฑ

POSIX์—์„œ๋Š” ์‰ฝ๊ฒŒ ์“ฐ๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

#include <pthread.h>
int pthread_create(
			pthread_t*      thread,
	  const pthread_attr_t* attr,
			void*           (*start_routine)(void*),
			void*           arg);

POSIX(Portable Operating System Interface)๋Š” ์šด์˜์ฒด์ œ ๊ฐ„์— ์ด์‹์„ฑ(Portability)์„ ๋†’์ด๊ธฐ ์œ„ํ•œ API(Application Programming Interface)์™€ ๋ช…๋ น์–ด ์…‹ ๋“ฑ์„ ์ •์˜ํ•˜๋Š” ํ‘œ์ค€์ž…๋‹ˆ๋‹ค. ์ด ํ‘œ์ค€์€ IEEE(Institute of Electrical and Electronics Engineers)์— ์˜ํ•ด IEEE 1003 ์‹œ๋ฆฌ์ฆˆ๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” ๋ช…์„ธ๋กœ ์ •์˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. POSIX๋Š” ์ฃผ๋กœ UNIX์™€ UNIX-like ์‹œ์Šคํ…œ(์˜ˆ: Linux, macOS)์—์„œ ์‚ฌ์šฉ๋˜๋ฉฐ, ์ด ํ‘œ์ค€์„ ๋”ฐ๋ฅด๋Š” ์šด์˜์ฒด์ œ์—์„œ๋Š” ๋™์ผํ•œ ๋˜๋Š” ์œ ์‚ฌํ•œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•จ์œผ๋กœ์จ, ์†Œํ”„ํŠธ์›จ์–ด์˜ ์ด์‹์„ฑ์„ ๋†’์ž…๋‹ˆ๋‹ค.

POSIX ํ‘œ์ค€์—๋Š” ํŒŒ์ผ ์‹œ์Šคํ…œ, ํ”„๋กœ์„ธ์Šค ๊ด€๋ฆฌ, ์Šค๋ ˆ๋“œ ๊ด€๋ฆฌ, ์ž…์ถœ๋ ฅ, ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ๋“ฑ ๋‹ค์–‘ํ•œ ๋ถ€๋ถ„์ด ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ pthread_create ํ•จ์ˆ˜๋Š” POSIX ์Šค๋ ˆ๋“œ(POSIX Threads, ๋˜๋Š” Pthreads)๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ C ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ•จ์ˆ˜ ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์šด์˜์ฒด์ œ๊ฐ€ ์ง€์›ํ•˜๋Š” ์Šค๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

thread๋Š” pthread_t ํƒ€์ž… ๊ตฌ์กฐ์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ์ด๋‹ค. ์ด ๊ตฌ์กฐ์ฒด๊ฐ€ ์“ฐ๋ ˆ๋“œ์™€ ์ƒํ˜ธ์ž‘์šฉํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.

attr์€ ์“ฐ๋ ˆ๋“œ์˜ ์†์„ฑ์„ ์ง€์ •ํ•œ๋‹ค. ์Šคํƒ์˜ ํฌ๊ธฐ, ์Šค์ผ€์ค„๋ง ์šฐ์„ ์ˆœ์œ„ ๊ฐ™์€ ์ •๋ณด๋ฅผ ์ง€์ •ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉํ•œ๋‹ค. ๋Œ€๋ถ€๋ถ„์€ NULL์„ ์ „๋‹ฌํ•ด์„œ ๋””ํดํŠธ ๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค.

start_routine์€ ์ด ์“ฐ๋ ˆ๋“œ๊ฐ€ ์‹คํ–‰ํ•  ํ•จ์ˆ˜๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค. C์–ธ์–ด์˜ ํ•จ์ˆ˜ ํฌ์ธํ„ฐ๋ฅผ ํ†ตํ•ด ์ „๋‹ฌํ•œ๋‹ค.

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

int add(int a, int b) {
    return a + b;
}

int (*func_ptr)(int, int);

func_ptr = add;

int result = func_ptr(2, 3);  // ๊ฒฐ๊ณผ๋Š” 5

---

void apply(int *arr, int size, int (*operation)(int)) {
    for(int i = 0; i < size; ++i) {
        arr[i] = operation(arr[i]);
    }
}

int square(int n) {
    return n * n;
}

// ์‚ฌ์šฉ ์˜ˆ
int numbers[] = {1, 2, 3, 4, 5};
apply(numbers, 5, square);

---

int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }

// ํ•จ์ˆ˜ ํฌ์ธํ„ฐ ๋ฐฐ์—ด
int (*operations[])(int, int) = {add, subtract};

// ์‚ฌ์šฉ ์˜ˆ
int result1 = operations[0](10, 5);  // add ํ•จ์ˆ˜ ํ˜ธ์ถœ, ๊ฒฐ๊ณผ๋Š” 15
int result2 = operations[1](10, 5);  // subtract ํ•จ์ˆ˜ ํ˜ธ์ถœ, ๊ฒฐ๊ณผ๋Š” 5

void* ํƒ€์ž…์˜ ์ธ์ž๋ฅผ ๋ฐ›๊ณ , void* ํƒ€์ž…์˜ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

arg๋Š” ์‹คํ–‰ํ•  ํ•จ์ˆ˜์—๊ฒŒ ์ „๋‹ฌํ•  ์ธ์ž๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค. ์™œ void* ํƒ€์ž…์ธ๊ฐ€? ์–ด๋–ค ๋ฐ์ดํ„ฐ ํƒ€์ž…๋„ ์ธ์ž๋กœ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๊ณ , ์–ด๋–ค ํƒ€์ž…์˜ ๊ฒฐ๊ณผ๋„ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

#include <stdio.h>
#include <pthread.h>

typedef struct {
	int a;
	int b;
} myarg_t;

void *mythread(void *arg) {
	myarg_t *args = (myarg_t *) arg;
	printf("%d %d\n", args->a, args->b);
	return NULL;
}

int main(int argc, char *argv[]) {
	pthread_t p;
	myarg_t args = { 10, 20 };
	int rc = pthread_create(&p, NULL, mythread, &args);
    ...
 

2. ์“ฐ๋ ˆ๋“œ ์ข…๋ฃŒ

๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ž‘์—…์„ ์™„๋ฃŒํ•  ๋•Œ๊ฐ€์ง€ ๊ธฐ๋‹ค๋ ค์•ผ ํ•œ๋‹ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ? POSIX ์“ฐ๋ ˆ๋“œ์—์„œ๋Š” pthread_join()์„ ํ˜ธ์ถœํ•˜๋ฉด ๋œ๋‹ค.

int pthread_join(pthread_t thread, void **value_ptr);

๋‘ ๊ฐœ์˜ ์ธ์ž๋ฅผ ๋ฐ›๋Š”๋‹ค. ์ฒซ ๋ฒˆ์งธ๋Š” ์–ด๋–ค ์“ฐ๋ ˆ๋“œ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋ ค๊ณ  ํ•˜๋Š”์ง€ ๋ช…์‹œํ•œ๋‹ค. ์ด ๋ณ€์ˆ˜๋Š” ์•„๊นŒ ์“ฐ๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ์ดˆ๊ธฐํ™”๋˜์—ˆ๋‹ค. ๋‘ ๋ฒˆ์งธ ์ธ์ž๋Š” ๋ฐ˜ํ™˜ ๊ฐ’์— ๋Œ€ํ•œ ํฌ์ธํ„ฐ์ด๋‹ค.

#include <stdio.h>
#include <pthread.h>
#include <assert.h>
#include <stdlib.h>

typedef struct { int a; int b; } myarg_t;
typedef struct { int x; int y; } myret_t;

void *mythread(void *arg) {
	myret_t *rvals = malloc(sizeof(myret_t));
	rvals->x = 1;
	rvals->y = 2;
	return (void *) rvals;
}

int main(int argc, char *argv[]) {
	pthread_t p;
	myret_t *rvals;
	myarg_t args = { 10, 20 };
	pthread_create(&p, NULL, mythread, &args);
	pthread_join(p, (void **) &rvals);
	printf("returned %d %d\n", rvals->x, rvals->y);
	free(rvals);
	return 0;
}
void *mythread(void *arg) {
	myarg_t *args = (myarg_t *) arg;
	printf("%d %d\n", args->a, args->b);
	myret_t oops; // ALLOCATED ON STACK: BAD!
	oops.x = 1;
	oops.y = 2;
	return (void *) &oops;
}

pthread_join()์—์„œ ๋ฐ˜ํ™˜ ๊ฐ’์„ ๋ฐ›์„ ๋•Œ, ๋™์  ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ , ์Šคํƒ์— ํ• ๋‹นํ•˜๋ฉด ์•ˆ๋œ๋‹ค. ์“ฐ๋ ˆ๋“œ๊ฐ€ ์ข…๋ฃŒ๋˜๋ฉด, oops ๊ฐ’์€ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋ฆฌํ„ดํ•  ๋•Œ ์ž๋™์œผ๋กœ ํ•ด์ œ๋œ๋‹ค. ํ˜„์žฌ ํ•ด์ œ๋œ ๋ณ€์ˆ˜๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ํฌ์ธํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ฒƒ์€ ์ข‹์ง€ ์•Š๋‹ค.

์‚ฌ์‹ค pthread_create()๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ƒ์„ฑํ•˜๊ณ , ์งํ›„์— pthread_join()ํ•ด์„œ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๊ฒƒ ๋ณด๋‹ค๋Š”, ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•ด ๋†“๊ณ , ์“ฐ๋ ˆ๋“œ๊ฐ€ ๋๋‚˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๊ฒƒ์ด ๋ณดํ†ต์ด๋‹ค.

ํ•˜์ง€๋งŒ ๋ชจ๋“  ๋ฉ€ํ‹ฐ ์“ฐ๋ ˆ๋“œ ์ฝ”๋“œ๊ฐ€ ์กฐ์ธ ๋ฃจํ‹ด์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์›น์„œ๋ฒ„์˜ ๊ฒฝ์šฐ, ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ž‘์—…์ž ์“ฐ๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋ฉ”์ธ ์“ฐ๋ ˆ๋“œ๋ฅผ ์ด์šฉํ•˜์—ฌ ์‚ฌ์šฉ์ž ์š”์ฒญ์„ ๋ฐ›์•„ ์ž‘์—…์ž์—๊ฒŒ ์ „๋‹ฌํ•˜๋Š” ์ž‘์—…์„ ๋ฌดํ•œํžˆ ํ•  ๊ฒƒ์ด๋‹ค. ์ด๋Ÿฐ ํ”„๋กœ๊ทธ๋žจ์€ join์„ ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค. ํ•˜์ง€๋งŒ, ํŠน์ • ์ž‘์—…์„ ๋ณ‘๋ ฌ์ ์œผ๋กœ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•ด ์“ฐ๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ณ‘๋ ฌ ํ”„๋กœ๊ทธ๋žจ์˜ ๊ฒฝ์šฐ์—๋Š”, ์ข…๋ฃŒ ์ „ ํ˜น์€ ๊ณ„์‚ฐ์˜ ๋‹ค์Œ ๋‹จ๊ณ„๋กœ ๋„˜์–ด๊ฐ€๊ธฐ ์ „์— ๋ณ‘๋ ฌ ์ˆ˜ํ–‰์ด ๋ชจ๋‘ ์™„๋ฃŒ๋˜์—ˆ๋‹ค๋Š” ๊ฒƒ์„ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด join์„ ์‚ฌ์šฉํ•œ๋‹ค.

Apache Tomcat

3. ๋ฝ

์“ฐ๋ ˆ๋“œ์˜ ์ƒ์„ฑ๊ณผ ์กฐ์ธ ๋‹ค์Œ์œผ๋กœ ๊ฐ€์žฅ ์œ ์šฉํ•œ ํ•จ์ˆ˜๋Š” ๋ฝ(lock)์„ ํ†ตํ•œ ์ž„๊ณ„ ์˜์—ญ์— ๋Œ€ํ•œ ์ƒํ˜ธ ๋ฐฐ์ œ ๊ธฐ๋ฒ•์ด๋‹ค.

int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

pthread_mutex_t lock;
pthread_mutex_lock(&lock);
x = x + 1;
pthread_mutex_unlock(&lock);

์‚ฌ์‹ค ์ด ์ฝ”๋“œ๋Š” ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š๋‹ค. ์šฐ์„  ์ดˆ๊ธฐํ™”๋ฅผ ํ•˜์ง€ ์•Š์•˜๋‹ค.

POSIX ์“ฐ๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๋ฝ์„ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋‘ ๊ฐ€์ง€์ด๋‹ค. ํ•œ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด PTHREAD_MUTEX_INITIALIZER๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด๋‹ค. pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; ์œ„ ์—ฐ์‚ฐ์€ ๋ฝ์„ ๋””ํดํŠธ ๊ฐ’์œผ๋กœ ์„ค์ •ํ•œ๋‹ค. ๋™์ ์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ (์ฆ‰, ์‹คํ–‰ ์ค‘์—) ๋‹ค์Œ๊ณผ ๊ฐ™์ด pthread_mutex_init()์„ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

int rc = pthread_mutex_init(&lock, NULL);
assert(rc == 0); // ์„ฑ๊ณตํ–ˆ๋Š”์ง€ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค.

๋˜ ์ด๋ ‡๊ฒŒ ์„ฑ๊ณตํ–ˆ๋Š”์ง€ ํ™•์ธํ•ด์ค˜์•ผ ํ•œ๋‹ค. ๋ฝ ์‚ฌ์šฉ์ด ๋๋‚ฌ๋‹ค๋ฉด pthread_mutex_destroy()๋„ ํ˜ธ์ถœํ•ด์•ผ ํ•œ๋‹ค.

๊ฐ„๋‹จํžˆ ๋งํ•ด์„œ, pthread_mutex_init(&lock, NULL);์€ lock์ด๋ผ๋Š” ์ด๋ฆ„์˜ ๋ฎคํ…์Šค๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๋ช…๋ น์ž…๋‹ˆ๋‹ค. ์ดํ›„์—๋Š” ์ด lock ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ pthread_mutex_lock(&lock) ๋˜๋Š” pthread_mutex_unlock(&lock) ๋“ฑ์˜ ๋ฎคํ…์Šค ๊ด€๋ จ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฝ๊ณผ ์–ธ๋ฝ ์™ธ์—๋„ ๋ฝ ๊ด€๋ จ ๋ฃจํ‹ด๋“ค์ด ๋” ์กด์žฌํ•œ๋‹ค.

int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_timedlock(pthread_mutex_t *mutex,
							struct timespec *abs_timeout);

trylock์€ ๋ฝ์ด ์ด๋ฏธ ์‚ฌ์šฉ ์ค‘์ด๋ผ๋ฉด ์‹คํŒจ ์ฝ”๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. timedlock์€ ํƒ€์ž„์•„์›ƒ์ด ๋๋‚˜๊ฑฐ๋‚˜ ๋ฝ์„ ํš๋“ํ•˜๊ฑฐ๋‚˜ ๋‘˜ ์ค‘ ํ•˜๋‚˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๋ฆฌํ„ดํ•œ๋‹ค. ์ด ๋‘ ํ•จ์ˆ˜๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ข‹์ง€๋งŒ, ๋ฝ ํš๋“ ๋ฃจํ‹ด์—์„œ ๋ฌดํ•œ์ • ๋Œ€๊ธฐํ•˜๋Š” ์ƒํ™ฉ์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๊ธฐ๋„ ํ•œ๋‹ค.

4. ์ปจ๋””์…˜ ๋ณ€์ˆ˜

int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_signal(pthread_cond_t *cond);

์ปจ๋””์…˜ ๋ณ€์ˆ˜๋Š” ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ ํ™˜๊ฒฝ์—์„œ ํŠน์ • ์กฐ๊ฑด์ด ์ถฉ์กฑ๋˜์—ˆ์„ ๋•Œ ์Šค๋ ˆ๋“œ๋“ค์—๊ฒŒ ์•Œ๋ ค์ฃผ๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์ž…๋‹ˆ๋‹ค. POSIX (Portable Operating System Interface) ํ‘œ์ค€์— ๋”ฐ๋ผ, C์–ธ์–ด์—์„œ๋Š” pthread_cond_wait, pthread_cond_signal ๋“ฑ์˜ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ปจ๋””์…˜ ๋ณ€์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;

// ์Šค๋ ˆ๋“œ 1
pthread_mutex_lock(&lock);
while (ready == 0) {
	pthread_cond_wait(&cond, &lock);
}
pthread_mutex_unlock(&lock);

// ์Šค๋ ˆ๋“œ 2
pthread_mutex_lock(&lock);
ready = 1; // while (ready == 0) ํƒˆ์ถœ
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);

์ปจ๋””์…˜ ๋ณ€์ˆ˜ ์‚ฌ์šฉ์„ ์œ„ํ•ด์„œ๋Š” ์ด ์ปจ๋””์…˜ ๋ณ€์ˆ˜์™€ ์—ฐ๊ฒฐ๋œ ๋ฝ์ด ๋ฐ˜๋“œ์‹œ ์กด์žฌํ•ด์•ผ ํ•œ๋‹ค. ์ฆ‰, ์œ„์— ๋‘ ํ•จ์ˆ˜ ์ค‘ ํ•˜๋‚˜๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๊ทธ ๋ฝ์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์•ผ ํ•œ๋‹ค.

์ฒซ ๋ฒˆ์งธ ๋ฃจํ‹ด pthread_cond_wait()๋Š” ํ˜ธ์ถœ ์“ฐ๋ ˆ๋“œ๋ฅผ ์ˆ˜๋ฉด (sleep) ์ƒํƒœ๋กœ ๋งŒ๋“ค๊ณ  ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๋กœ๋ถ€ํ„ฐ์˜ ์‹œ๊ทธ๋„์„ ๋Œ€๊ธฐํ•œ๋‹ค. ํ˜„์žฌ ์ˆ˜๋ฉด ์ค‘์ธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ๊ด€์‹ฌ ์žˆ๋Š” ๋ฌด์–ธ๊ฐ€๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฉด ์‹œ๊ทธ๋„์„ ๋ณด๋‚ธ๋‹ค.

์‹œ๊ทธ๋„ ๋Œ€๊ธฐ ํ•จ์ˆ˜์—์„œ๋Š” ๋ฝ์„ ๋‘ ๋ฒˆ์งธ ์ธ์ž๋กœ ๋ฐ›๊ณ  ์žˆ์ง€๋งŒ, ์‹œ๊ทธ๋„ ๋ณด๋‚ด๊ธฐ ํ•จ์ˆ˜์—์„œ๋Š” ์กฐ๊ฑด๋งŒ์„ ์ธ์ž๋กœ ๋ฐ›๋Š” ๊ฒƒ์— ์œ ์˜ํ•ด์•ผ ํ•œ๋‹ค. ์ด๋Ÿฐ ์ฐจ์ด์˜ ์ด์œ ๋Š” ์‹œ๊ทธ๋„ ๋Œ€๊ธฐ ํ•จ์ˆ˜๋Š” ํ˜ธ์ถœ ์“ฐ๋ ˆ๋“œ๋ฅผ ์žฌ์šฐ๋Š” ๊ฒƒ ์™ธ์— ๋ฝ๋„ ๋ฐ˜๋‚ฉ (release)ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

pthread_cond_wait()๋Š” ๊นจ์–ด๋‚˜์„œ ๋ฆฌํ„ดํ•˜๊ธฐ ์ง์ „์— ๋ฝ์„ ๋‹ค์‹œ ํš๋“ํ•œ๋‹ค. ์ฒ˜์Œ ๋ฝ์„ ํš๋“ํ•œ ๋•Œ๋ถ€ํ„ฐ ๋งˆ์ง€๋ง‰์— ๋ฝ์„ ๋ฐ˜๋‚ฉํ•  ๋•Œ๊นŒ์ง€ pthread_cond_wait()๋ฅผ ์‹คํ–‰ํ•œ ์“ฐ๋ ˆ๋“œ๋“ค์€ ํ•ญ์ƒ ๋ฝ์„ ํš๋“ํ•œ ์ƒํƒœ๋กœ ์‹คํ–‰๋œ๋‹ค๋Š” ๊ฒƒ์„ ๋ณด์žฅํ•œ๋‹ค.

๋‘ ์“ฐ๋ ˆ๋“œ ๊ฐ„์— ์‹œ๊ทธ๋„์„ ์ฃผ๊ณ  ๋ฐ›์•„์•ผ ํ•  ๋•Œ, ๋ฝ๊ณผ ์ปจ๋””์…˜ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹  ๊ฐ„๋‹จํ•œ ํ”Œ๋ž˜๊ทธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

// ์Šค๋ ˆ๋“œ 1
while (ready == 0); // spinlock

// ์Šค๋ ˆ๋“œ 2
ready = 1;

์ด๋Ÿฐ ๋ฐฉ๋ฒ•์€ ์ข‹์€ ๋ฐฉ๋ฒ•์ด ์•„๋‹ˆ๋‹ค. ์กฐ๊ฑด ๊ฒ€์‚ฌ๋ฅผ ์œ„ํ•ด ์˜ค๋žซ๋™์•ˆ ๋ฐ˜๋ณต๋ฌธ์„ ์‹คํ–‰ํ•˜์—ฌ ๊ฒ€์‚ฌํ•˜๋Š” ๊ฒƒ์€ ํšจ์œจ์ ์ด์ง€ ๋ชปํ•˜๋‹ค. ๋˜ ์ด๋ ‡๊ฒŒ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ์‹ค์ˆ˜ํ•˜๊ธฐ ๋งค์šฐ ์‰ฝ๋‹ค.

์ปจ๋””์…˜ ๋ณ€์ˆ˜๊ฐ€ ์•„์ง ์ž˜ ์ดํ•ด๊ฐ€ ๋˜์ง€ ์•Š์•„๋„, ์ดํ›„ ์žฅ์—์„œ ์ž์„ธํžˆ ๋‹ค๋ฃฐ ๊ฒƒ์ด๋‹ค.

5. ์ปดํŒŒ์ผ๊ณผ ์‹คํ–‰

-pthreadํ”Œ๋ž˜๊ทธ๋ฅผ ๋ช…๋ น์–ด ๋งํฌ ์˜ต์…˜ ๋ถ€๋ถ„์— ์ถ”๊ฐ€ํ•˜์—ฌ ์‚ฌ์šฉํ•˜์—ฌ pthread ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ๋งํฌํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ช…์‹œํ•ด์•ผ ํ•œ๋‹ค.

prompt> gcc โˆ’o main main.c โˆ’Wall โˆ’pthread