์์ ์๊ฐํ ์ฐ๋ ๋๋ฅผ ๋ค๋ฃจ๋ ๋ฐฉ๋ฒ์ ๋ํด ์์๋ณด์.
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์ ์ฌ์ฉํ๋ค.
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