1. Thread์ ๊ฐ๋
Thread์ ์ข ๋ฅ
Thread๋ ํฌ๊ฒ ๋ ๊ฐ์ง๋ก ๋๋ฉ๋๋ค.
- User Thread: ์ปค๋์ ์ง์ ์ ์ธ ์ง์ ์์ด ์ฌ์ฉ์ ๊ณต๊ฐ์์ ๊ด๋ฆฌ๋ฉ๋๋ค.
- Kernel Thread: ์ปค๋์ด ์ง์ ๊ด๋ฆฌํ๋ ์ฐ๋ ๋์ ๋๋ค.
User Thread์ Kernel Thread ๊ฐ์ ๊ด๊ณ ๋ชจ๋ธ
- Many-to-One Model: ์ฌ๋ฌ ๊ฐ์ user thread๊ฐ ํ๋์ kernel thread์ ๋งคํ๋ฉ๋๋ค.
- One-to-One Model: ๊ฐ๊ฐ์ user thread๊ฐ ํ๋์ kernel thread์ ๋งคํ๋ฉ๋๋ค.
- Many-to-Many Model: ์ฌ๋ฌ ๊ฐ์ user thread๊ฐ ์ฌ๋ฌ ๊ฐ์ kernel thread์ ๋งคํ๋ฉ๋๋ค.
![]() |
![]() |
![]() |
2. Thread ๋ผ์ด๋ธ๋ฌ๋ฆฌ
Thread ์์ฑ๊ณผ ๊ด๋ฆฌ๋ฅผ ์ํด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ํ์ํ๋ฉฐ, ๋ํ์ ์ธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- POSIX Pthreads (Linux, Unix ํ๊ฒฝ)
- Windows Thread (Windows ํ๊ฒฝ)
- Java Thread (JVM ๊ธฐ๋ฐ)
์ด๋ฒ ์ค์ต์์๋ POSIX Pthreads๋ฅผ ์ด์ฉํ์ฌ thread๋ฅผ ์์ฑํ๊ณ ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ์ ์ค์ตํด ๋ณด๊ฒ ์ต๋๋ค.
3. Pthreads ์ค์ต
3.1 Pthreads ์ค์ต 1: ๊ฐ๋จํ Thread ์์ฑ ๋ฐ ์คํ
#include <stdio.h>
#include <stdlib.h> // atoi() ํจ์ ์ฌ์ฉ (๋ฌธ์์ด์ ์ ์๋ก ๋ณํ)
#include <pthread.h> //POSIX Thread ๋ผ์ด๋ธ๋ฌ๋ฆฌ
int sum; //์ ์ญ ๋ณ์ ์ ์ธ
void *runner(void *param); //์ฐ๋ ๋์์ ์คํ๋ ํจ์ ์ ์ธ
int main(int argc, char *argv[]) //argc: ๋ช
๋ น์ค ์ธ์ ๊ฐ์, argv: ๋ช
๋ น์ค ์ธ์ ๋ฐฐ์ด
{
pthread_t tid; //์ฐ๋ ๋ ์์ด๋๋ฅผ ์ ์ฅํ๋ ๋ณ์
pthread_attr_t attr; //์ฐ๋ ๋ ์์ฑ์ ์ ์ฅํ๋ ๋ณ์
pthread_attr_init(&attr); //์ฐ๋ ๋ ์์ฑ ์ด๊ธฐํ
pthread_create(&tid, &attr, runner, argv[1]); // runner ํจ์ ์คํ, argv[1] ์ ๋ฌ
pthread_join(tid, NULL); // Thread๊ฐ ์ข
๋ฃ๋ ๋๊น์ง ๋๊ธฐ (๋ฉ์ธ ํจ์๊ฐ ๋จผ์ ๋๋์ง ์๊ฒ)
printf("sum = %d\n", sum);
}
void *runner(void *param)
{
int i, upper = atoi(param); //atoi๋ก ๋ฌธ์์ด์ ์ ์๋ก ๋ณํ
sum = 0;
for (i = 1; i <= upper; i++)
sum += i;
pthread_exit(0); //์คํ์ด ๋๋ฌ์์ ์๋ฆฌ๊ณ ์ข
๋ฃ
}
์คํ ์์
gcc -pthread pthread_example1.c -o pthread_example1
./pthread_example1 10
-> sum = 55
์ฝ๋ ์ค๋ช
- pthread_create()๋ฅผ ์ด์ฉํ์ฌ ์๋ก์ด ์ฐ๋ ๋๋ฅผ ์์ฑํ๊ณ runner ํจ์๋ฅผ ์คํํฉ๋๋ค.
- pthread_join()์ ํธ์ถํ์ฌ ๋ฉ์ธ ์ฐ๋ ๋๊ฐ ์๋กญ๊ฒ ์์ฑ๋ ์ฐ๋ ๋๊ฐ ์ข ๋ฃ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฝ๋๋ค.
- runner ํจ์๋ ์ ๋ฌ๋ upper ๊ฐ์ ๊ธฐ๋ฐ์ผ๋ก 1๋ถํฐ ํด๋น ๊ฐ๊น์ง์ ํฉ์ ๊ณ์ฐํฉ๋๋ค.
ํฌ์ธํฐ ๊ฐ๋
์ ๋ง์ด ๊น๋จน์ด์ ์์ ์์ ํฌ์ธํฐ ์ฐ์ฌ์ง ๋ถ๋ถ ์ ๋ฆฌ
1๏ธโฃ void *runner(void *param);
๐ void *runner
- void * → ํฌ์ธํฐ๋ฅผ ๋ฐํํ๋ ํจ์๋ผ๋ ๋ป
- ์ฆ, runner() ํจ์๋ ์ด๋ค ๋ฐ์ดํฐ ํ์ ์ด๋ ๊ฐ๋ฆฌํฌ ์ ์๋ ํฌ์ธํฐ๋ฅผ ๋ฐํํ ์ ์์์ ์๋ฏธ.
- ํ์ง๋ง ์ค์ ๋ก๋ pthread_exit(0);์ผ๋ก ๋๋๊ธฐ ๋๋ฌธ์ ๋ฐํ๊ฐ์ ์ฌ์ฉํ์ง ์์.
๐ void *param
- param ์์ *๋ ํฌ์ธํฐ ๋งค๊ฐ๋ณ์๋ผ๋ ๋ป.
- ์ฆ, param์ ์ด๋ค ๋ฐ์ดํฐ ํ์ ์ด๋ ๊ฐ๋ฆฌํฌ ์ ์๋ ํฌ์ธํฐ.
- pthread_create()๋ก ์๋ก์ด ์ฐ๋ ๋๋ฅผ ๋ง๋ค ๋, ์คํํ ํจ์์ ๋งค๊ฐ๋ณ์๋ก ํฌ์ธํฐ ํ๋๋ง ์ ๋ฌํ ์ ์์.
- ๊ทธ๋์ param์ void * ํ์ ์ผ๋ก ์ ์ธํด์ ์ด๋ค ํ์ ์ด๋ ๋ฐ์ ์ ์๋๋ก ํจ.
๐ก ์ ํฌ์ธํฐ(void *param)๋ฅผ ์ฐ๋ ๊ฑธ๊น?
์ฐ๋ ๋๋ฅผ ๋ง๋ค ๋, ์คํํ ํจ์์ ํ๋์ ๋งค๊ฐ๋ณ์๋ง ๋๊ธธ ์ ์๊ธฐ ๋๋ฌธ.
→ ๋ค์ํ ๋ฐ์ดํฐ ํ์
์ ๋๊ธฐ๋ ค๋ฉด ํฌ์ธํฐ๋ฅผ ์ฌ์ฉํด์ผ ํจ.
2๏ธโฃ pthread_create(&tid, &attr, runner, argv[1]);
๐ &tid → ์ฐ๋ ๋ ID ์ ์ฅํ ๊ณต๊ฐ์ ์ ๋ฌ
- tid๋ ์ฐ๋ ๋ ID๋ฅผ ์ ์ฅํ ๋ณ์.
- pthread_create()๋ ์๋ก์ด ์ฐ๋ ๋๋ฅผ ๋ง๋ค๋ฉด์ ๊ทธ ์ฐ๋ ๋์ ID๋ฅผ tid์ ์ ์ฅํด์ผ ํจ.
- ํ์ง๋ง C์์ ํจ์๊ฐ ๊ธฐ๋ณธ์ ์ผ๋ก ๊ฐ์ ๋ณต์ฌํด์ ์ ๋ฌํ๊ธฐ ๋๋ฌธ์,
๊ฐ์ ์ ์ฅํ๋ ค๋ฉด ๋ณ์์ ์ฃผ์๋ฅผ ๋๊ฒจ์ผ ํด. - ๊ทธ๋์ &tid๋ฅผ ๋๊ฒจ์ tid ๋ณ์ ์์ฒด๋ฅผ ๋ณ๊ฒฝํ ์ ์๋๋ก ํด์ผ ํจ.
๐ &attr → ์ฐ๋ ๋ ์์ฑ ๊ตฌ์กฐ์ฒด ์ ๋ฌ
- pthread_attr_t๋ ์ฐ๋ ๋ ์์ฑ(์คํ ํฌ๊ธฐ, ์ฐ์ ์์ ๋ฑ)์ ์ ์ฅํ๋ ๊ตฌ์กฐ์ฒด.
- pthread_attr_init(&attr);์์ ์์ฑ์ ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์ด๊ธฐํํ ํ, pthread_create()์ ํฌ์ธํฐ(&attr)๋ฅผ ์ ๋ฌํด์ผ ํจ.
- ๊ทธ๋์ผ pthread_create() ํจ์๊ฐ attr์ ์ง์ ์ฝ์ ์ ์์.
๐ก ์ ์ฃผ์๋ฅผ ๋๊ธธ๊น?
- C ์ธ์ด์์ ๊ตฌ์กฐ์ฒด๋ฅผ ํจ์์ ์ ๋ฌํ๋ฉด ๊ฐ์ด ๋ณต์ฌ๋จ.
- ๋ณต์ฌ๋ณธ์ ์ ๋ฌํ๋ฉด ์๋ณธ์ ์์ ํ ์ ์๊ธฐ ๋๋ฌธ์, ์๋ณธ์ ์์ ํ๋ ค๋ฉด ์ฃผ์๋ฅผ ๋๊ฒจ์ผ ํจ.
3๏ธโฃ argv[1]์ ์ ๊ทธ๋ฅ ๋๊ธฐ๋?
- argv[1]์ ๋ฌธ์์ด(char *)์ด๊ธฐ ๋๋ฌธ์, ์๋๋ถํฐ ํฌ์ธํฐ ํํ์ผ.
- ๊ทธ๋์ ๊ตณ์ด &argv[1]์ ๋๊ธธ ํ์ ์์ด, ๊ทธ๋ฅ argv[1]์ ์ ๋ฌํ๋ฉด ๋จ.
3.2 Pthreads ์ค์ต 2: Thread์ fork()๋ฅผ ํจ๊ป ์ฌ์ฉํ๋ ๊ฒฝ์ฐ
#include <stdio.h>
#include <unistd.h> //fork(), getpid() ์ฌ์ฉ
#include <wait.h>
#include <pthread.h>
int value = 0; //์ ์ญ๋ณ์, ๋ชจ๋ ํจ์์์ ์ ๊ทผ ๊ฐ๋ฅ
void * runner(void *param);
int main(int argc, char *argcv[])
{
pid_t pid; //fork()๊ฐ ๋ฐํํ๋ ํ๋ก์ธ์ค ID๋ฅผ ์ ์ฅํ๋ ๋ณ์.
pthread_t tid; //์ฐ๋ ๋ ID๋ฅผ ์ ์ฅํ๋ ๋ณ์.
pthread_attr_t attr; //์ฐ๋ ๋ ์์ฑ์ ์ ์ฅํ๋ ๊ตฌ์กฐ์ฒด.
pid = fork(); //์์ ํ๋ก์ธ์ค ์์ฑ
if(pid ==0) { //child process
pthread_attr_init(&attr);
pthread_create(&tid, &attr, runner, NULL); //์ฐ๋ ๋ ์์ฑ ๋ฐ ์คํ
pthread_join(tid, NULL); //์ฐ๋ ๋ ์ข
๋ฃ๊น์ง ๋๊ธฐ
printf("CHILD: value = %d\n", value);
}
else if (pid > 0) { //parent process
wait(NULL); //์์ ํ๋ก์ธ์ค ์ข
๋ฃ๊น์ง ๋๊ธฐ
printf("PARENT: value = %d\n", value); //์์ ํ๋ก์ธ์ค ๋๋๋ฉด ์ถ๋ ฅ
}
}
void *runner(void *param)
{
value = 5;
pthread_exit(0);
}
์คํ ์์
CHILD: value = 5
PARENT: value = 0โ
์คํ ๊ฒฐ๊ณผ ๋ถ์
- ์์ ํ๋ก์ธ์ค์์ ์ฐ๋ ๋๋ฅผ ์์ฑํ์ฌ value ๊ฐ์ ๋ณ๊ฒฝํ๋ฉด, ๋ถ๋ชจ ํ๋ก์ธ์ค๋ ์ํฅ์ ๋ฐ์ง ์์ต๋๋ค.
- fork() ์ดํ ์์ฑ๋ ํ๋ก์ธ์ค๋ ๋ ๋ฆฝ๋ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ ๊ฐ์ง๋ฏ๋ก, ์ฐ๋ ๋๊ฐ ๋ณ๊ฒฝํ ๊ฐ์ด ๋ถ๋ชจ ํ๋ก์ธ์ค์๋ ๋ฐ์๋์ง ์์ต๋๋ค.
์ถ๊ฐ ๊ฐ๋ : Thread์ Process์ ์ฐจ์ด
- Thread๋ ๊ฐ์ ํ๋ก์ธ์ค ๋ด์์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ณต์ ํฉ๋๋ค.
- Process๋ ๋ ๋ฆฝ๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ฐ์ง๋ฏ๋ก, ํ ํ๋ก์ธ์ค์ ๋ณ๊ฒฝ ์ฌํญ์ด ๋ค๋ฅธ ํ๋ก์ธ์ค์ ์ํฅ์ ๋ฏธ์น์ง ์์ต๋๋ค.
3.3 Pthreads ์ค์ต 3: fork()์ Thread ์์ฑ
#include <stdio.h>
#include <unistd.h>
#include <wait.h>
#include <pthread.h>
void *runner(void *param);
int main(int argc, char *argv[])
{
pid_t pid;
pthread_t tid;
printf("A = %d\n", getpid());
pid = fork(); //์ฒซ ๋ฒ์งธ fork ์คํ, ์์์ pid ๋ฐํ
if(pid > 0) {
wait(NULL); //์์ ์ข
๋ฃ๊น์ง ๋๊ธฐ
printf("B = %d\n", pid);
}
if(pid == 0) { //์์ ํ๋ก์ธ์ค
pid = fork();
if(pid > 0) { //๋ค์ fork
wait(NULL); //์ฒซ ๋ฒ์งธ ์์ ๋๊ธฐ
if (pid > 0) printf("C = %d\n", pid);
}
pthread_create(&tid, NULL, runner, NULL); //๋ ๋ฒ์งธ ์์ ์ค๋ ๋ ์์ฑ, runner ์คํ
}
pid = fork(); //๋ชจ๋ ํ๋ก์ธ์ค์์ fork ์คํ
if(pid > 0) {
wait(NULL);
if (pid > 0) printf("D = %d\n", pid);
}
}
void *runner(void *param)
{
printf("I'm a thread!\n");
pthread_exit(0);
}
์คํ ์์
A = 9332
I'm a thread!
D = 9336
C = 9334
I'm a thread!
D = 9338
B = 9333
D = 9339
๋ถ์
์๋์ ๊ฐ์ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง๋ฉฐ, fork()์ pthread_create()๋ฅผ ์ฌ์ฉํ์ฌ ํ๋ก์ธ์ค
์ ์ฐ๋ ๋๋ฅผ ์์ฑํฉ๋๋ค.
pid_t pid;
pid = fork();
if(pid == 0) { /* child process */
fork();
pthread_create(...);
}
fork();
ํ๋ก์ธ์ค ๋ฐ ์ฐ๋ ๋ ๊ฐ์ ๋ถ์
a. Unique Process ๊ฐ์: 6๊ฐ
b. Unique Thread ๊ฐ์: 2๊ฐ
๊ณผ์ ์ค๋ช
- A (๋ถ๋ชจ ํ๋ก์ธ์ค)๊ฐ B (์์ ํ๋ก์ธ์ค)๋ฅผ ์์ฑํฉ๋๋ค.
- B๊ฐ fork()๋ฅผ ํธ์ถํ์ฌ C๋ฅผ ์์ฑํฉ๋๋ค.
- B์ C๋ ๊ฐ๊ฐ pthread_create()๋ฅผ ํธ์ถํ์ฌ ์ฐ๋ ๋๋ฅผ ์์ฑํ๊ณ "I'm a thread!"๋ฅผ ์ถ๋ ฅํฉ๋๋ค.
- ์ดํ A, B, C ๋ชจ๋ fork()๋ฅผ ์คํํ์ฌ D, D, D ํ๋ก์ธ์ค(์ด 3๊ฐ)๋ฅผ ์ถ๊ฐ๋ก ์์ฑํฉ๋๋ค.
์ด ์ค์ต์ ํตํด fork()์ pthread_create()์ ์ํธ ์์ฉ์ ์ดํดํ๊ณ , ํ๋ก์ธ์ค์ ์ฐ๋ ๋๊ฐ ์ด๋ป๊ฒ ์์ฑ๋๋์ง ์ค์ตํ ์ ์์ต๋๋ค.
4. Implicit Threading
์ฐ๋ ๋์ ์์ฑ๊ณผ ๊ด๋ฆฌ๋ฅผ ๋์ฑ ์ฝ๊ฒ ํ๊ธฐ ์ํด Implicit Threading ๊ธฐ๋ฒ์ด ๋ฑ์ฅํ์ต๋๋ค. ๋ํ์ ์ธ ๊ธฐ๋ฒ์ผ๋ก๋ ๋ค์์ด ์์ต๋๋ค.
- Thread Pools: ๋ฏธ๋ฆฌ ์์ฑ๋ ์ฐ๋ ๋ ํ์์ ์ฐ๋ ๋๋ฅผ ์ฌ์ฌ์ฉํ๋ ๋ฐฉ์.
- Fork & Join Model: ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ฅผ ๋ช ์์ ์ผ๋ก ์ง์ ํ๋ ๋ฐฉ์.
- OpenMP: ์ปดํ์ผ๋ฌ ์ง์์ด๋ฅผ ์ฌ์ฉํ์ฌ ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ฅผ ๊ตฌํ.
4.1 OpenMP ์ค์ต 1: ๊ธฐ๋ณธ์ ์ธ ๋ณ๋ ฌ ์คํ
#include <stdio.h>
#include <omp.h>
int main(int argc, char *argv[])
{
#pragma omp parallel
{
printf("I am a parallel region.\n");
}
return 0;
}
์คํ ๋ฐฉ๋ฒ
gcc -fopenmp openmp_example1.c -o openmp_example1
./openmp_example1
4.2 OpenMP ์ค์ต 2: ์ฌ๋ฌ ๊ฐ์ ์ฐ๋ ๋ ํ์ฉ
#include <stdio.h>
#include <omp.h>
int main(int argc, char *argv[])
{
omp_set_num_threads(4);
#pragma omp parallel
{
printf("OpenMP thread: %d\n", omp_get_thread_num());
}
return 0;
}
์คํ ์์
OpenMP thread: 1
OpenMP thread: 3
OpenMP thread: 0
OpenMP thread: 2
์ฐ๋ ๋์ ์คํ ์์๋ ๋ณด์ฅ๋์ง ์์ต๋๋ค.
5. ๋ง๋ฌด๋ฆฌ
์ด๋ฒ ๊ธ์์๋ pthread์ ๊ธฐ๋ณธ ๊ฐ๋ ๊ณผ ์ค์ต์ ์งํํ์์ผ๋ฉฐ, fork()์์ ๊ด๊ณ, OpenMP๋ฅผ ํ์ฉํ ๋ณ๋ ฌ ์ฒ๋ฆฌ๊น์ง ์ดํด๋ณด์์ต๋๋ค.
์ถ๊ฐ ํ์ต ์ถ์ฒ
- mutex, semaphore๋ฅผ ํ์ฉํ ๋๊ธฐํ ๊ธฐ๋ฒ
- pthread_cond_wait() ๋ฐ pthread_cond_signal()์ ์ด์ฉํ ์กฐ๊ฑด ๋ณ์
- ๋ณ๋ ฌ ํ๋ก๊ทธ๋๋ฐ์ ์ฑ๋ฅ ์ต์ ํ ๊ธฐ๋ฒ
์ค์ต์ ํตํด ์ฐ๋ ๋์ ์์ฑ, ๊ณต์ ๋ฉ๋ชจ๋ฆฌ ํ์ฉ, ๋ณ๋ ฌ ํ๋ก๊ทธ๋๋ฐ ๊ธฐ๋ฒ์ ์ตํ๋ ๋ฐ ๋์์ด ๋์๊ธฐ๋ฅผ ๋ฐ๋๋๋ค.