Hello, pthread!
3๋ ๊ฐ ์ฐ์ ๊ธฐ๋ฅ์์์ผ๋ก ๋ณต๋ฌด ํ๊ณ , ๋ณตํํด ์ปด๊ณต๊ณผ ์์ ์ ๋ฃ๊ณ ์์ต๋๋ค. ๊ทธ๋์ ๋ง์ด ๋ฐฐ์ ๋ค๊ณ ์๊ฐํ๋๋ฐ, ์ฌ์ ํ ๋ถ์กฑํ ๋ถ๋ถ์ด ๋ง๋ค์ ^^;; ์ญ์ ์ธ์๋ ๋๊ณ ๊ณต๋ถ์ ๊ธธ๋ ๋์ ๊ฒ ๊ฐ์ต๋๋ค.
๋ค์ด๊ฐ๋ฉฐ
ํ๊ต ์ด์์ฒด์ ์์ ์ ๊ฐ์ ์ฌ๋ผ์ด๋์ โ์๊ฒ thread๋ฅผ ์ฌ์ฉํ๋ ์ฝ๋ ์์์์^^โ๋ผ๋ฉฐ ์ฝ๋ ์กฐ๊ฐ์ด ๋ฉ๊ทธ๋ฌ๋ ์์๋ค. ์ง๊ธ๊น์ง ๋์ ๊ฐ์ข ์๊ฒฉ์ฆ ์ํ๊ณผ ์ฝํ ๊ฒฝํ์ ๋ฏธ๋ฃจ์ด๋ดค์ ๋, ์ฝ๋๋ฅผ ๊ทธ๋ฅ ์ฝ๋ ๊ฑด ๋จธ๋ฆฟ์์ ์ ๋จ์ง ์์์๋ค;; ๊ทธ๋์ ๊ฐ์ ์ฌ๋ผ์ด๋์ ๋์จ ์ฝ๋ ์กฐ๊ฐ๋ค์ C๋ก ์ฎ๊ฒจ์ ์ง์ ์ง๋ณด๋ ค๊ณ ํ๋ค!!
์๊ฒ ์๋ ๊ฐ์ ์ฌ๋ผ์ด๋์ ์๋ ์ฝ๋ ์์์ด๋ค. C์ธ์ด์ ๋น์ทํ์ง๋ง, ์์ ํ ๋์ผํ์ง ์๋ค. ์ด๋ฒ ํฌ์คํธ์ ๋ชฉํ๋ ์๋ ํจ์๋ค์ ๊ฒฝํํด๋ณด๋ ๊ฒ์ด๋ค.
thread_create()
thread_exit()
thread_join()
Hello, pthread!
์ ์ผ ๋จผ์ pthread_create()
์ผ๋ก ์ฐ๋ ๋๋ฅผ ๋ง๋ค์ด๋ณด์.
#include <stdio.h>
#include <pthread.h>
#define NTHREADS 10
pthread_t threads[NTHREADS];
๊ทธ์ ์ ๋จผ์ pthread ์ฌ์ฉ์ ์ํด ํ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ pthread.h
๋ฅผ ๋ถ๋ฌ์ค๊ณ , ๊ฐ์ข
์ ์ญ ๋ณ์๋ฅผ ์ ์ธํด๋๋ค. pthread_t
๋ pthread ์ ๋ณด๋ฅผ ๋ด๋ ๊ตฌ์กฐ์ฒด์ด๋ค. ์์ โpโ๊ฐ ๋ถ๋ ์ด์ ๋ POSIX์์ ์๊ตฌํ๋ ์ฐ๋ ๋ ๊ธฐ๋ฅ์ ๊ฐ์ถ์๊ธฐ ๋๋ฌธ์ด๋ผ๊ณ ํ๋ค.
Callee Function
void* go (void* args) {
int* n = (int*) args;
printf("Hello from thread %d\n", *n);
}
์ผ๋จ ์ฐ๋ ๋๋ก ์คํ์ํฌ go()
๋ผ๋ ํจ์๋ฅผ ์ ์ํด์ผ ํ๋๋ฐ, ์ด ํจ์๋ ๋ฆฌํด๊ณผ ํจ์ ์ธ์๊ฐ ๋๋ค void*
ํ์
์ด๋ค. void*
ํ์
์ ์ฒ์ ๋ง์ฃผํ์ฌ ์ด์ํ ์ ์์ผ๋ ์ฒจ์ธํ์๋ฉดโฆ (๋ณธ์ธ๋ void*
ํ์
์ ์ด๋ฒ์ OS ๋ค์ผ๋ฉด์ ์ฒ์ ๋ดค๋ค ใ
ใ
)
int
ํ์
๊ณผ char
ํ์
์ ๊ฐ๊ฐ 4 byte์ 1 byte๋ก ๋ค๋ฅธ ์ฌ์ด์ฆ๋ฅผ ๊ฐ์ต๋๋ค. ๋ฐ๋ฉด์ ํฌ์ธํฐ ๋ณ์๋ ๋ชจ๋ ์ฐธ๊ณ ํ๋ ๋ณ์์ ์ฃผ์๊ฐ(address)๋ฅผ ๋ด๊ธฐ ๋๋ฌธ์ ๋ชจ๋ 4 bytes ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํฉ๋๋ค. ๊ทธ๋์ ๋ชจ๋ ํฌ์ธํฐ ๋ณ์๋ ์ฌ์ค ๊ฐ์ ํ์
์ด๋ผ๊ณ ๋ณผ ์ ์์ต๋๋ค.
ํฌ์ธํฐ ๋ณ์๋ฅผ ์ ์ธํ ๋ int*
, char*
๋ก ํ์
์ ๊ณ๋ค์ฌ ์ฌ์ฉํ์ง ์๋?๋ผ๊ณ ์๋ฌธ์ ์ ์ํ ์ ์์ต๋๋ค๋ง, ์ ๊ธฐ์ ๋ถ๋ int
์ char
๋ ํฌ์ธํฐ ๋ณ์๊ฐ ์ฐธ์กฐํ๋ ๋ณ์์ ํ์
์ ๋งํ ๋ฟ์
๋๋ค. ๊ทธ๋์ ์๋์ ๊ฐ์ ์ฝ๋๋ ์ ํจํ๊ฒ ๋์ํฉ๋๋ค.
int a = 10;
char* p = (char*) &a;
(char*)
๋ผ๊ณ ํฌ์ธํฐ ํ์
์ ๋ํ ์บ์คํ
์ด ๋ค์ด๊ฐ์ง๋ง, int
๋ณ์์ ์ฃผ์๊ฐ์ด long*
ํ์
ํฌ์ธํฐ์ ๊ฐ์ผ๋ก ๋ค์ด๊ฐ๋๊ฒ ๊ฐ๋ฅํฉ๋๋ค.
void*
๋ ์ด๋ฐ ํฌ์ธํฐ ๋ณ์์ ํน์ฑ์ ํ์ฉํด, ์์ ํฌ์ธํฐ ๋ณ์๊ฐ ์ฐธ์กฐํ๋ ๋ณ์๊ฐ ๋ฌด์์ธ์ง ๋ช
์ํ์ง ์๋ ํจํด์
๋๋ค. ๊ทธ๋์ int*
๊ฐ ๋ ์๋ ์๊ณ , float*
๊ฐ ๋ ์๋ ์๊ณ , ๊ทธ ์ด๋ค ํฌ์ธํฐ ํ์
๋ ๋ ์ ์์ต๋๋ค. ์๊ฑธ โvoid ํฌ์ธํฐโ๋ผ๊ณ ๋ถ๋ฆ
๋๋ค.
void ํฌ์ธํฐ๋ฅผ ์ฐ๋ฉด ์๋์ ๊ฐ์ ์ฝ๋๋ฅผ ์งค ์ ์์ต๋๋ค.
int a = 10;
void* p = &a;
*((int*) p) = 20;
๋ง์ฝ ํ์
์บ์คํ
์์ด *p = 20;
๋ก ์ฐ๋ ค๊ณ ํ๋ค๋ฉด, void ํฌ์ธํฐ๊ฐ ์ฐธ์กฐํ๋ ๋ณ์๊ฐ ์ด๋ค ์ฌ์ด์ฆ์ธ์ง ๋ชฐ๋ผ์ ๋ฐ์ดํฐ๋ฅผ RW ํ ์ ์์ ๊ฒ ์
๋๋ค. ๊ทธ๋์ (int*)
์บ์คํ
์ ํด์ค์ผ ํฉ๋๋ค.
pthread_create
์ด์ main ํจ์์์ pthread_create()
๋ก ์ฐ๋ ๋๋ฅผ ์์ฑํด๋ณด์.
int main(void) {
int thread_args[NTHREADS];
for (int i=0; i < NTHREADS; i++) {
thread_args[i] = i;
pthread_create(&threads[i], NULL, go, &thread_args[i]);
}
return 0;
}
pthread_create(&threads[i], NULL, go, &thread_args[i])
์ ๊ฐ์ด ์ฌ์ฉํ์๋๋ฐ, ๊ฐ ์ธ์์ ์๋ฏธ๋ฅผ ์ ์ผ๋ฉด ์๋์ ๊ฐ๋ค. ๋ช
์ธ๋ linux man page๋ฅผ ์ฐธ๊ณ ํ๋ค.
pthread_t *restrict thread
pthread_t
ํฌ์ธํฐ ๋ณ์restrict
๋ ๊ทธ ํฌ์ธํฐ๊ฐ ์ฐธ๊ณ ํ๋ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋ ๋ค๋ฅธ ํฌ์ธํฐ๊ฐ ์กด์ฌํ์ง ์๋๋ค๋ ๊ฑธ ๋งํ๋ค. C์ธ์ด ์ปดํ์ผ ๋ ์ต์ ํ์ ์ฌ์ฉํ๋ ํค์๋๋ค.
const pthread_attr_t *restrict attr
- ์๋ก ๋ง๋ค์ด์ง๋ ์ฐ๋ ๋์ ํน์ฑ๊ฐ(attribution)์ ์ ์ํ๋ค.
- ์ด๋ฒ ํฌ์คํธ์์๋ ์ฌ์ฉํ์ง ์์์
NULL
๋ก ์ฒ๋ฆฌํ๋ค.
void *(*start_routine)(void *)
- ์ฐ๋ ๋๋ก ์คํํ ํจ์๋ฅผ ์ ๋ฌํ๋ค. ์ธ์์ ๋ฆฌํด ํ์
์ด ๋๋ค
void*
์ฌ์ผ ํ๋ค.
- ์ฐ๋ ๋๋ก ์คํํ ํจ์๋ฅผ ์ ๋ฌํ๋ค. ์ธ์์ ๋ฆฌํด ํ์
์ด ๋๋ค
void *restrict arg
start_routine
ํจ์์ ์ ๋ฌํ ํจ์ ์ธ์๋ฅผ ์ ์ํ๋ค. ์๊ฒ๋ ํฌ์ธํฐ๋ก ์ ๋ฌํ๋ค!
์ด๋ ๊ฒ ์ ์ํ ์ํ์์ ์ฝ๋๋ฅผ ์ปดํ์ผ ํ๊ณ ์คํํด๋ณด๋ฉด,
$ gcc threadHello.c
$ ./a.out
Hello from thread 0
Hello from thread 1
Hello from thread 7
Hello from thread 3
์?? 10๊ฐ ์ฐ๋ ๋๋ฅผ ๋ง๋๋ ค๊ณ ํ๋๋ฐ, 4๊ฐ ์ ๋ ๋ง๋ค๊ณ ์คํ์ด ์ข ๋ฃ ๋์๋ค ๐ค ๊ทธ ์ด์ ๋ Thread Join์ ํ์ง ์์๊ธฐ ๋๋ฌธ์ด๋ค!!
Argument passing
Thread create ๋, ์ด๋ค ํจ์๋ฅผ ์ฐ๋ ๋๋ก ์คํํ ์ง๋ ์ ๋ฌํ์ง๋ง, ๊ทธ ํจ์์ ์ด๋ค ์ธ์๋ก ์คํํ ์ง๋ void* args
ํจ์๋ก ์ ๋ฌํ๋ค.
void* go (void* args) {
int* n = (int*) args; // get value from args
printf("Hello from thread %d\n", *n);
}
int main(void) {
int thread_args[NTHREADS];
for (int i=0; i < NTHREADS; i++) {
thread_args[i] = i;
pthread_create(&threads[i], NULL, go, &thread_args[i]); // pass args
}
return 0;
}
์ฌ๊ธฐ ์ฝ๋์์๋ ์ ์๊ฐ i
์ ๊ฐ์ ์ธ์๋ก ๋๊ฒจ์ฃผ๋ ค๊ณ ํ๋ค. ์ด๋, &i
๋ก ๋ฐ๋ก ๋๊ธฐ์ง ์๊ณ , thread_args[i]
์ ๋ด์์ ๊ฐ์ ์ ๋ฌํ๋ค. ๊ทธ ์ด์ ๋ &i
๋ก ๋ฐ๋ก ๋๊ธฐ๋ฉด, i
๋ณ์๋ฅผ ๋ชจ๋ ์ฐ๋ ๋์์ ์ ๊ทผํ๋ ๊ผด์ด ๋๊ธฐ ๋๋ฌธ์ด๋ค.
pthread_join
int main(void) {
// Thread Create
...
for (int i=0; i < NTHREADS; i++) {
pthread_join(threads[i], NULL);
printf("Thread %d returned\n", i);
}
printf("Main thread done\n");
}
pthread_join()
๋ ์ด๋ค ์ฐ๋ ๋์ signal์ ๋ฐ์ ๊ฑด์ง ์ ํด์ค์ผ ํ๋ค.
pthread_t thread
- ์์์
pthread_create()
๋๋pthread_t
์ ํฌ์ธํฐ๋ฅผ ์ฌ์ฉ ํ๋๋ฐ, join์์๋ ์ฐ๋ ๋ ๋ณ์ ๊ทธ ์์ฒด๋ฅผ ์ฌ์ฉํ๋ค.
- ์์์
void **retval
- ๋ค์์ ๋ค๋ฃฐ ๊ฑฐ์ง๋ง,
pthread_exit()
์ผ๋ก ๋ถ๋ชจ ์ฐ๋ ๋์๊ฒ signal์ ์ค ์ ์๋๋ฐ, ๊ทธ๋ ์ ๋ฌ ๋ฐ์ ๊ฐ์ ๊ธฐ๋กํ๊ธฐ ์ํ ์ธ์์ด๋ค. - ์ง๊ธ์
NULL
์ ์ฌ์ฉํ์ง๋ง, ๊ณง ๋ค์์retval
์ ์ฐ๋ ์์๋ ๋ณผ ์์ !
- ๋ค์์ ๋ค๋ฃฐ ๊ฑฐ์ง๋ง,
๊ทธ๋ฆฌ๊ณ ์ฝ๋๋ฅผ ์ปดํ์ผ ํด์ ์ดํด๋ณด๋ฉดโฆ
$ ...
Hello from thread 0
Hello from thread 4
Hello from thread 6
Hello from thread 8
Hello from thread 1
Hello from thread 5
Hello from thread 2
Hello from thread 7
Hello from thread 3
Hello from thread 9
Thread 0 returned
Thread 1 returned
Thread 2 returned
...
Thread 7 returned
Thread 8 returned
Thread 9 returned
Main thread done
์ด๋ฒ์๋ ์์ฑํ ์ฐ๋ ๋๊ฐ ๋ชจ๋ ์คํ๋์๋ค!! ์คํ ์์๋ ์ ๊ฐ๊ฐ์ด์ง๋ง, pthread_join()
ํ์ printf()
์ถ๋ ฅ ๋๋ ๊ฑด ์์๋๋ก ์งํ๋๋ค!
์ฐ๋ ๋๊ฐ ์์ฑ ๋ ํ, ์คํ์ ๋์์ ์งํ๋๋ค. ์คํ ๊ณผ์ ์์์ ์์๋ ์ ํด์ง ๋ฐ๊ฐ ์๋ค. ๋ค๋ง, pthread_join()
์ผ๋ก ์ข
๋ฃ signal์ ๋ฐ๊ธฐ ์ ์ ์ฐ๋ ๋์ ์์์ด ํด์ ๋์ง ์๊ณ ๋จ์์๋ค. ๋ฉํฐ ํ๋ก์ธ์ค๋ฅผ ์ด์ํ ๋๋ wait์ผ๋ก ์์ ํ๋ก์ธ์ค์ signal์ ๊ผญ ๋ฐ์์ผ ํ๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด zombie process1์ ๊ฐ์ ์ํฉ์ด ๋ฐ์ํ๋ค. ์ฐ๋ ๋๋ฅผ ์ด์ํ ๋๋ ๋น์ทํ๋ค. ๊ผญ join์ ํตํด ์์ ์ฐ๋ ๋์ signal์ ๋ฐ๊ณ , ์์ ์ฐ๋ ๋๋ฅผ ํ ๋น ํด์ ์ฒ๋ฆฌํด์ค์ผ ํ๋ค.
pthread_exit
์ด๋ฒ์๋ ์์ ์ฐ๋ ๋์์ pthread_exit()
์ผ๋ก ์ฐ๋ ๋๋ฅผ ์ข
๋ฃํ๋ฉด์, ๋ถ๋ชจ ์ฐ๋ ๋์๊ฒ ๊ฒฐ๊ณผ๋ฅผ ๋๊ฒจ์ฃผ๋ ์์๋ฅผ ์ดํด๋ณด์.
void* go (void* args) {
int* n = (int*) args;
printf("Hello from thread %d\n", *n);
*n += 100;
pthread_exit(n); // return value to parent thread
}
int main(void) {
// Thread Create
...
for (int i=0; i < NTHREADS; i++) {
void* return_value; // pointer to get returned value
pthread_join(threads[i], &return_value);
printf("Thread %d returned %d\n", i, *((int*) return_value));
}
printf("Main thread done\n");
return 0;
}
์ฃผ๋ชฉํ ๋ถ๋ถ์ pthread_exit(n);
๋ถ๋ถ๊ณผ pthread_join(threads[i], &return_value);
๋ถ๋ถ์ด๋ค.
์์ ์ฐ๋ ๋๋ pthread_exit(n)
์ผ๋ก ์ฐ๋ ๋๋ฅผ ์ข
๋ฃํ๋ฉฐ, ๋ถ๋ชจ ์ฐ๋ ๋์๊ฒ ๊ฐ์ ๋๊ฒจ์ค๋ค. ์ด๋, ๊ฐ ์์ฒด๋ฅผ ๋๊ฒจ์ฃผ๋๊ฒ ์๋๋ผ ํฌ์ธํฐ ๋ณ์ int* n
์ ๋๊ฒจ์ค๋ค.
๋ถ๋ชจ ์ฐ๋ ๋๋ pthread_join()
์ผ๋ก ์์ ์ฐ๋ ๋์ ์ข
๋ฃ ์ํ๋ฅผ ํ์ํ๋ค. ์ด๋, void* return_value
๋ฅผ ์ฌ์ฉํด ํด๋น ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ๊ธฐ๋กํ๋๋ฐ, ์ข
๋ฃ ์ํ๋ฅผ ๊ธฐ๋กํ ์ฃผ์ ์์น ๋ฐ์์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ ๊ฒ์ด๋ค. ๊ทธ๋์ &return_value
๋ก ์ฌ์ฉํ ๊ฒ.
References
- Pardue University
- ํ์๋์ ๋ธ๋ก๊ทธ
- SUS Ver2
- Linux man pages
-
์์ ํ๋ก์ธ์ค๊ฐ ๋ถ๋ชจ ํ๋ก์ธ์ค ๋ณด๋ค ๋จผ์ ์ข ๋ฃ ๋์์ง๋ง, ๋ถ๋ชจ ํ๋ก์ธ์ค๊ฐ wait์ผ๋ก ์ข ๋ฃ ์ํ๋ฅผ ํ์ ํ์ง ์์ ์ํย ↩