티스토리 뷰

Study/OS

[OS] POSIX Thread

생각많은 소심남 2013. 6. 25. 16:34

일전에 이런 내용을 다룬 적이 있다.

2013/02/15 - [About School] - [Study] Task / Thread

그 때 이야기 하기론 thread는 Process를 처리하는 일종의 Worker의 개념으로 설명했었다. 당연히 이 Thread가 여러개 있어서 concurrent하게 Process를 처리하는 구조인 MultiThread를 지향하는 방향이다. 물론 Process가 어떤 위치에 있느냐에 따라서 Thread의 중요성도 다를 것이다. 예를 들어 웹 브라우저나 워드프로세서같은 User Process를 처리하는 Thread 도 있을 것이고, 일반적으로 발생하는 Kernel Process를 처리하는 Thread도 있을 것이다. 물론 Kernel Process를 처리하는 Kernel Thread는 운영체제단에서 daemon과 같은 형태로 지원이 된다. 리눅스에서 Thread에 관한 내용을 thread_struct에서 가지고 있다.


< /arch/x86/include/asm/processor.h : 밑에 Damn you 라는 주석이 인상적이다.>


주석도 달려있다시피 가장 밑단의 소스이기 때문에 cpu의 register를 건드리는 변수들이 많이 있다. 그런데 여기서 다루는 건 task_struct내에 있는 thread의 구조체인 것이고, 실제로 kernel_thread를 살펴보는 thread정보는 ptrace.h에 들어있다.


</arch/x86/include/asm/ptrace.h> 


여기도 역시 cpu register들이 정의되어 있다. 이게 실제로 쓰이는 부분은 process.c라는 파일에 들어 있다.



일전에 linux에선 thread는 light weighted Process라는 말을 했었는데 그 말처럼 역시 thread의 생성에는 마지막에 do_fork(), 즉 child process를 생성하는 것과 마찬가지로 생성한다. 이와 같이 우리가 잘알고 있는 OS인 Windows, Mac OS, Linux는 Kernel Thread를 지원한다. 

 반면 사용자가 이 Process를 처리하는 thread,즉 User Thread를 사용하기 위해서는 말그대로 User level에서 사용할 수 있는 thread library 를 활용해야 한다. 가장  대표적인 library가 POSIX standard library인 Pthread이다. 말 그대로 POSIX Thread 라는 뜻인데 궁금한 사람은 이전 포스트를 참고하면 될 거 같다.

2013/02/21 - [About School] - [Study] POSIX

이밖에도 windows계열에서 사용할 수 있는 Win32 Thread나 Java Thread가 있다.


간단한 예제를 통해서 Pthread 사용법을 정리해보고자 한다. Process생성에도 몇가지 기본적인 함수들이 있었던 것처럼 Thread 생성에 있어서도 가장 기본적인 함수가 create, Join, Exit이다. Create는 말 그대로 thread를 생성하는 함수인데, 이외에도 return 값을 통해서 error checking을 할 수 있다. 가령 error가 발생했을 경우에는 -1을 return 하게 된다. Join은  Process 생성시 사용했던 함수 중에 wait과 유사한 함수이다. 그래서 thread 생성시 다른 thread가 종료될 때까지 기다리는 역할을 수행한다. exit은 말 그대로 calling state를 terminate 시키는 함수다.


자 그럼 간단한 예제를 만들어본다. 우선 pthread를 활용하기 위해서는 앞에서 언급한 것처럼 pthread.h를 포함시켜야 하며, 지금 보여주는 예제는 Thread의 생성과 Join이 제대로 되는지를 확인하는 것이다. 코드는 다음과 같다. 

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 #include <stdlib.h>
  4 #include <string.h>
  5 #include <pthread.h>
  6 
  7 void *thread_function(void *arg);
  8 char message[] = "Test Thread";
  9 
 10 int main()
 11 {
 12 	int num;
 13 	pthread_t test_thread;
 14 	void *thread_result;
 15 
 16 	num = pthread_create(&test_thread, NULL, thread_function, (void *)message);
 17 
 18 	if(num != 0){
 19 		perror("Thread creation failed!");
 20 		exit(EXIT_FAILURE);
 21 	}
 22 
 23 	printf("Waiting for thread to finish..\n");
 24 
 25 	num = pthread_join(test_thread, &thread_result);
 26 
 27 	if(num != 0){
 28 		perror("Thread Join Failed!");
 29 		exit(EXIT_FAILURE);
 30 	}
 31 
 32 	printf("Thread joined, return value : %s\n", (char *)thread_result);
 33 	printf("Message is now %s\n", message);
 34 	exit(EXIT_SUCCESS);
 35 }
 36 
 37 void *thread_function(void *arg)
 38 {
 39 	printf("thread_function executed. Argument is %s\n", (char *)arg);
 40 	sleep(3);
 41 	strcpy(message, "finish!");
 42 
 43 	pthread_exit((void *)"Finished thread_function");
 44 }


위 코드의 동작을 살펴보자면 thread function이라는 함수를 생성하고 create를 통해서 호출하는 형식을 취하고 있다. 그러고 난 후에 test_thread를  또 join 시키고 있다. 만약 정상적으로 수행된다면 create에서 출력되는 message와 join했을 때의 message값, 나중에 빠져나왔을 때의 값이 전부 다를 것이다.

 그럼 컴파일을 해야 되는데 지금 위 코드는 pthread를 사용하기 때문에 컴파일시에도 이에 대한 플래그를 세워야 한다. 결국 다음과 같이 컴파일하면 결과를 얻을 수 있다.


두번째는 thread function을 하나 삽입하고 main과 동시에 수행하게끔 하는 예제이다.


  1 #include <stdio.h>
  2 #include <pthread.h>
  3 #include <stdlib.h>
  4 
  5 void *thread_function(void *arg);
  6 
  7 int thread_num = 1;
  8 
  9 int main()
 10 {
 11 	int num;
 12 	pthread_t test_thread;
 13 	void *thread_result;
 14 	int count = 0;
 15 
 16 	num = pthread_create(&test_thread, NULL, thread_function, NULL);
 17 
 18 	while(count++ < 20){
 19 		if(thread_num == 1){
 20 			printf("1");
 21 			thread_num = 2;
 22 		}
 23 		else
 24 			sleep(1);
 25 	}
 26 
 27 	printf("\nWaiting for thread to finish...\n");
 28 	num = pthread_join(test_thread, &thread_result);
 29 	printf("thread joined!\n");
 30 	exit(EXIT_SUCCESS);
 31 }
 32 
 33 void *thread_function(void *arg)
 34 {
 35 	int count = 0;
 36 
 37 	while(count++ < 20){
 38 		if(thread_num == 2){
 39 			printf("2");
 40 			thread_num = 1;
 41 		}
 42 		else
 43 			sleep(1);
 44 	}
 45 }


잘보면 thread_num이 1로 되어 있는 상태에서 새로운 thread를 생성하고 thread_num을 2로 바꾸었다. 이렇게 하면 thread_function 내에서 조건문이 반응하고 2를 출력하게 된다. 이 같은 과정이 반복하면 20번씩 1과 2를 출력하게 된다. 결과는 다음과 같다.



간단하게 pthread를 사용하는 방법에 대해 알아보았다. 뭐 조금더 궁금한 사람은 /usr/include/pthread.h 파일을 살펴보면 thread 사용시 쓰는 구조체나 함수의 틀을 확인해볼 수 있다..

'Study > OS' 카테고리의 다른 글

[Process] Exceptional Control  (0) 2014.08.28
[Memory] Memory Consideration in OS  (0) 2013.11.26
[OS] Context Switch  (0) 2013.06.29
[Process] Inter Process Communication (IPC)  (5) 2013.06.21
[Process] Process Creation  (0) 2013.06.20
[Memory] Memory Addressing  (2) 2013.06.20
[Process] Process Scheduling  (1) 2013.06.20
댓글