user thread : 사용자 스레드는 커널 영역의 상위에서 지원되며 일반적으로 사용자 레벨의 라이브러리
를 통해 구현되며, 라이브러리는 스레드의 생성 및 스케줄링 등에 관한 관리 기능을 제공합니다.
동일한 메모리 영역에서 스레드가 생성 및 관리되므로 속도가 빠른 장점이 있는 반면, 여러 개의 사용자 스레드 중 하나의 스레드가 시스템 호출 등으로 중단되면 나머지 모든 스레드 역시 중단되는 단점이 있습니다. 이는 커널이 프로세스 내부의 스레드를 인식하지 못하며 해당 프로세스를 대기 상태로 전환시키기 때문입니다.
kernel thread : 커널 스레드는 운영체제가 지원하는 스레드 기능으로 구현되며, 커널이 스레드의 생성 및 스케줄링 등을 관리합니다. 스레드가 시스템 호출 등으로 중단되더라도, 커널은 프로세스 내의 다른 스레드를 중단시키지 않고 계속 실행시켜줍니다. 다중처리기 환경에서 커널은 여러 개의 스레드를 각각 다른 처리기에 할당할 수 있습니다. 다만, 사용자 스레드에 비해 생성 및 관리하는 것이 느립니다.
여러 개의 사용자 수준 스레드들이 하나의 커널 스레드(프로세스)로 매핑되는 방식으로, 사용자 수준에서 스레드 관리가 이루어집니다. 주로 커널 스레드를 지원하지 않는 시스템에서 사용하며, 한 번에 하나의 스레드만이 커널에 접근할 수 있다는 단점이 있습니다.
하나의 스레드가 커널에 시스템 호출을 하면 나머지 스레드들은 대기해야 하기 때문에 진정한 의미의 동시성을 지원하지 못합니다. 다시 말해, 여러 개의 스레드가 동시에 시스템 호출을 사용할 수 없습니다. 또한 커널 입장에서는 프로세스 내부의 스레드들을 인식할 수 없고 하나의 프로세스로만 보이기 때문에 다중처리기 환경이라도 여러 개의 프로세서에 분산하여 수행할 수 없습니다.
이 모델을 사용중인 시스템은 거의 존재하지 않습니다.
사용자 스레드들을 각각 하나의 커널 스레드로 매핑시키는 방식입니다. 사용자 스레드가 생성되면 그에 따른 커널 스레드가 생성되는 것입니다. 이렇게 하면 다-대-일 방식에서 시스템 호출 시 다른 스레드들이 중단되는 문제를 해결할 수 있으며 여러 개의 스레드를 다중처리기에 분산하여 동시에 수행할 수 있는 장점이 있습니다.
그러나 커널 스레드도 한정된 자원을 사용하므로 무한정 생성할 수는 없기 때문에, 스레드를 생성할 때 그 개수를 염두에 두어야 합니다.
윈도우와 리눅스가 이 모델을 구현하고 있습니다.
여러 개의 사용자 스레드를 여러 개의 커널 스레드로 매핑시키는 모델입니다. 다-대-일 방식과 일-대-일 방식의 문제점을 해결하기 위해 고안되었습니다. 커널 스레드는 생성된 사용자 스레드와 같은 수 또는 그 이하로 생성되어 스케줄링합니다. 다-대-일 방식에서 스레드가 시스템 호출시 다른 스레드가 중단되는 현상과 일-대-일 방식에서 사용할 스레드의 수에 대해 고민하지 않아도 됩니다. 커널이 사용자 스레드와 커널 스레드의 매핑을 적절하게 조절합니다.
Thread library는 프로그래머에게 thread를 생성하고 관리하도록 API를 제공합니다.
스레드 라이브러리를 구현하는데에는 주된 두 가지 방법이 있는데,
kernel의 지원없이 완전히 user space에서만 library를 제공하는 것. 라이브러리의 함수를 호출하는 것은 시스템 호출이 아니라 사용자 공간의 지역함수를 호출하는 것이 됩니다.
운영체제에 의해 kernel space에서 구현하는 것. 라이브러리 API를 호출하는 것은 kernel system call을 부르는 결과를 낳습니다.
현재 아래 3가지 thread library가 주로 사용됩니다.
POSIX Pthreads: POSIX 표준 thread의 확장판이다. kernel 수준의 library이다. UNIX와 Linux system에서는 Pthreads로 구현된다.
Win32 threads: Windows system에서 제공되는 kernel 수준의 library이다.
Java threads: Java는 JVM 위에서 돌아가므로, JVM이 실행되고 있는 OS와 hardware에 기반해서 구현된다.
#include <stdio.h>
#include <pthread.h> //라이브러리 사용
int thread_args[3] = {0,1,2};
//함수이지만 스레드로 동작
//void * : 주소를 리턴. integer가 될지 뭐가 될지 잘 모르겠다(리턴값은 없다)
void *Thread(void *arg){
int i;
for(i=0; i<5; i++){
printf("thread %d: %dth iteration\n", *(int*)arg,i);
}
pthread_exit(0); //스레드 종료
}
void main(void){
int i;
pthread_t threads[3]; // 우리가 생성할 스레드를 위한 식별자
for(i=0; i<3; i++){
printf("Thread Num %d Create!!\n", i);
//스레드 생성. Thread실행 -> 인자로는 thread_args[i]의 주소
pthread_create(&threads[i],null,(void*(*)(void *))Thread, &thread_args[i]);
}
pthread_exit(0);
}
#include <conio.h>
#include <iostream.h>
#include <windows.h>
DWORD __stdcall ThreadFunc(LPVOID Param);
typedef struct stThreadParam{
int id;
int sleeptime;
} ThreadParam;
int main(){
HANDLE hThread[4];
DWORD ThreadID[4];
ThreadParam tp[4];
for(int i=0; i<4; i++){
tp[i].id = i;
tp[i].sleeptime = i*200;
// ThreadFunc 스레드를 만든다. 구조체 주소를 넘겨줌. 총 4개 생성
hThread[i] = CreateThread(Null, 0,ThreadFunc, &tp[i],0,&ThreadID[i]);
}
// 다 끝날때까지 기다림
WaitForMultipleObjects(4, hThread, TRUE,INFINITE);
getch();
return 0;
}
DWORD WINAPI ThreadFunc(LPVOID Param){
ThreadParam *tp = (ThreadParam *)Param;
for(int i=0; i<10; i++){
cout << end1;
cout << "Thread " << tp->id << ":" << i << end1;
sleep(tp->sleeptime);
// 나는 쉴테니 다른 놈 시켜도 됨. 자기는 ready 큐로 내려감
}
return 0;
}