본문 바로가기

STUDY/운영체제

multi-thread programming

앞에서 배운 multi-process programming은 마냥 좋기만 할까? 딱히 그렇지도 않다.

 

process

process는 기본적으로 Heavy-weight이다. 즉 프로세스 1개를 만드는 것은 오버헤드가 크다.

왜냐하면 process는 가진 정보가 많기 때문이다.

프로세스들은 독립적인 memory space가 필요하다. 따라서 address space가 필요하다. 또한 os resource, accounting info, hardware execution state(pc, sp, register) 등등 이러한 자료구조들을 새로 다 만들어야 한다. 당연히 오버헤드가 클 수 밖에 없다.

따라서 fork() 등으로 process를 새로 생성하는 것은 costly, 즉 비용이 많이 든다.

또한 통신을 위한 IPC도 마찬가지로 오버헤드가 크고 costly하다.

 

그럼 여러 프로세스로 concurrent 한 작업을 수행할 수 있는 다른 방법이 없을까?

여기서 스레드의 필요성이 만들어진다.


thread란 무엇인가?

 

thread는 cpu utilization의 기본 단위이다. 즉 프로세스 내의 실행의 흐름이다. thread, 즉 실이라는 영어 단어를 생각해보면 흐름이라는 표현이 이해가 된다. 흐름도 실처럼 흐물흐물

- program counter

- register set

- stack space

등의 hardware execution state를 개별적으로 가진다. 이를 제외하고 

code section, data section, os resource 들은 다른 스레드들과 공유한다.

 

process vs thread

- thread는 1개의 single process에 속해있다. 즉 process는 여러개의 thread를 가질 수 있다.

- thread간에 data space를 공유하는 것이 오버헤드도 줄일 수 있고 경제적이다.

- thread가 scheduling의 단위가 된다.

- process가 static, thread가 dynamic 한 성질을 가지게 된다.

 

multi process vs multi-thread

processs들은 fork()를 하는 순간 완전하게 독립된 영역에서 각각의 stack, data 영역을 사용한다. 그때마다 PCB와 memory 공간을 할당받아서 초기화하는 과정이 필요하다. (오버헤드 대박) 다른 process의 영역도 볼 수 없으므로 IPC라는 통신 방법도 필요하다.

프로세스 포스팅을 보고 오면 아주 좋음

2021.11.29 - [STUDY/운영체제] - process concept

 

반면에 thread의 stack은 따로 가지고 있지만, code와 data 영역은 공유한다. 즉 PCB와 memory 공간을 할당받아 초기화 하는 과정이 필요없다. 따라서 data 영역에 속하는 변수는 모든 스레드들이 접근 가능하므로 이를 이용하면 thread 간에 쉽고 빠른 통신이 가능하다. IPC같은 통신 방법이 필요가 없다.

 

따라서 thread를 여러개 만드는 것이 process 여러개 만드는 것보다 오버헤드가 작다. 하지만 thread하나가 비정상 종료되는 경우 같은 process의 다른 thread까지 문제가 전이될 수 있다. process는 독립적이므로 다른 process가 비정상 종료되든 말든 상관 없다.

따라서 장점들을 정리해보자면

 

benefits

- responsiveness

- resource sharing

- economy

- used for MP architecture


thread는 크게 두가지로 구분한다.

User-Threads

: user-level에서의 thread management이다. 대부분 library들로 구현되어있다.

예를 들면 우리가 많이 쓰는 리눅스에서의 posix-pthread, solaris 같은 것들이다.

속도가 빠르지만 운영체제가 직접 thread에게 interrupt를 걸 수 없다. 또한 thread가 user-mode에서 실행되므로 sys call이 발생했을 때의 대응이 어렵다.

 

Kernel-Threads

: kernel-level에서의 thread이다. 이는 thread의 생성과 management에 sys call이 필요하게 된다.

예를 들면 windows 98/95/2000, sloaris, linux, 등등이다.

kernel level이므로 모든 thread가 system call로 구현 가능하고 kernel이 직접적으로 thread의 scheduling도 하고 thread에게 interrupt도 걸 수 있다. kernel 단계의 수행시간이 늘어나면 오버헤드가 발생할 수도 있지만 여전히 처리가 좋다.

그림과 같이 kernel에 thread table이 있다.

 

 

user-level vs kernel level

 

user-level threads

- library가 thread를 관리한다. (ex. pthread.h)

- small and fast

- user level thread가 os에게 보이지 않는다.

- os가 처리하기 힘들다.

 

kernel-level threads

- thread를 os가 관리한다.

- os가 scheduling도 한다.

- process보다 cheap

- 그래도 os가 thread를 관리하는 것은 user-level에 비해서 costly이긴 함

 


Multi-threading models

- many-to-one: kernel thread는 1개이고 user thread를 여러개로 구현 => user-level thread

- one-to-one: 여러개의 kernel thread마다 1개의 user thread => 1개가 중지되어도 다른 것들은 영향이 없다.

- many-to-many: 여러개의 kernel thread에 여러개의 user thread => 다중 프로세스의 장점을 극대화한다.

 


하지만 이런 thread에도 구현하게 될때 문제가 있다.

Threading Issues

 

- fork()와 exec()의 문제

: fork를 thread안에서 한다면 두가지 선택사항이 생긴다.

 

ex. process 1개 안에 5개의 thread가 있다고 하면

1. thead가 6개?

2. process가 2개, thead가 10개?

 

- thread cancellation

: thread가 끝나기전에 강제종료할 수 있는가?

linux에서는 Pthread.h 라이브러리 안에 이를 제어할 수 있는 함수들로 제공한다.

int pthread_setcancelstate(int state, int *oldstate);
int pthread_setcanceltype(int type, int *oldtype);

 

setcancelstate는 enable, disable 두가지의 선택이 있고 강제 종료 할 수 있는지 선택 가능하다. 당연히 enable이 default

setcanceltype은 종료할 때의 option을 설정할 수 있다.

-> Asynchronous: 즉시 종료한다. 하지만 만약에 mutex lock을 가지고 있다가 강제종료되면 반납을 안하고 그냥 종료된다.

-> Deffered: therad가 가지고 있는 자원을 반납하고 종료한다. 영어 뜻처럼 잠시 미뤄두는 것이다.

 

- signal handling 

: signal 이 온 경우 어떤 thread가 이를 받아서 처리하는가?

linux에서는 main thread에서 시그널을 처리한다.

 

- thread pools

: 오버헤드가 process보다 작지만 어쨌든 자원의 한계가 있으므로 만들 수 있는 thread의 수를 정해놔야 한다.

 

- thread specific data

: thread들도 자신들만 접근가능한 data 영역이 필요할 수 있다.

 


<Pthread.h>

: IEE에서 정한 유닉스의 system call에 대한 표준이 POSIX이다. pthread는 posix thread의 표준이다.

이 라이브러리 안에 포함된 함수들은 다음과 같다.

 

thread creation

- pthread_create()

- pthread_exit()

- pthread_join()

 

mutex: thread의 동기화를 위해 만든 것이다. 

-pthread_mutex_init()

-pthread_mutex_destroy()

-pthread_mutex_lock()

-pthread_mutex_unlock()

-pthread_mutex_trylock()

 

mutex lock 과 항상 같이 쓰이는 condition variable

- pthread_cond_init()

- pthread_cond_wait()

- pthread_cond_signal()

- pthread_cond_destroy()

 

이 부분은 동기화 포스팅에서 자세하게 살펴보자

'STUDY > 운영체제' 카테고리의 다른 글

synchronization  (0) 2021.12.02
process scheduling  (0) 2021.12.01
process concept  (0) 2021.11.29
os system structure  (0) 2021.11.28
about operating system  (0) 2021.04.05