-> 블로그 이전

[OS] 3. 스레드

2022. 3. 26. 15:39Major`/운영체제

"거의 모든 현재 OS는 한 프로세스가 다중 스레드를 포함하는 특성을 제공한다"

 

스레드?

프로세스는 현재 실행중인 프로그램들이다. 그러면 스레드는?

"스레드는 CPU 이용의 기본 단위이다" , "프로세스 내부에서 실제로 작업을 수행하는 주체" ???

동일한 일을 수행하는데 여러개의 프로세스를 통해서 수행하면 각 프로세스마다 별도의 주소공간이 생성됨에 따라 메모리가 낭비되고 자원을 관리해주는 OS의 입장에서도 굉장히 힘들 것이다.

>> 그래서 동일한 일을 수행하는데 일단 프로세스는 하나만 생성해주고, 해당 프로세스안에 여러개의 스레드를 통해서 일을 나누어서 동시에 작업을 수행하면 더 효율적이다

  • 하나의 프로세스 내에서 여러 개의 실행 흐름(단일 / 동시 / 병렬)을 두어서 작업을 효율적으로 처리
  • 하나의 프로세스 내에서 더 작은 단위로 독립적으로 실행시키며 제어가 가능한 흐름
  • kernel들은 일반적으로 MultiThreaded이다

외부에서 보게되면 하나의 프로세스가 동시에 여러 작업을 수행하는 것처럼 보이게 된다

각 스레드별로 수행하는 작업이 다르다
이러한 이유 때문에 각 스레드는 (PC, 레지스터 값, stack)들을 별도로 유지해야 한다

  • CPU는 명령어 하나를 읽어와서 실행을 하는데 스레드는 해당 명령어에서 job을 서로 분배시켜서 작업을 하기 때문에 당연히 PC, 레지스터값들은 스레드마다 별도로 유지해야 한다
  • stack 공간 또한 각 스레드별로 호출되는 함수, 매개변수 등이 다르기 때문에 stack 공간도 스레드마다 별도로 존재해야 한다

>> 하나에서 공유할 수 있는 부분은 최대한 공유하고(메모리 주소 공간 & 프로세스 상태 & 프로세스가 사용하는 자원)

>>CPU 수행과 관련된 값(PC, 레지스터 값, stack)들은 별도로 보유해야 한다

 

다중 스레드 장점

1) 응답성 : Responsiveness

interactive적인 program인 경우, 해당 프로그램의 일부분이 blocking이 될 경우, 단일 스레드는 해당 프로그램 관련 일을 수행하지 못하는데, 멀티 스레드의 경우 일부분이 blocking되어도 다른 부분은 non-blocking이므로 계속 프로그램 수행이 가능하다

>> user에 대한 응답성을 증가시킨다

 

2) 자원 공유 : Resource Sharing

각 프로세스들이 자원을 서로 공유하려면 1) Shared Memory, 2) Message Passing과 같은 기법으로 자원을 공유해야 하는데, 이는 개발자가 명시적으로 처리해줘야 한다.
하지만 스레드는 프로세스 내부에서 자동적으로 프로세스가 사용하고 있는 자원, 메모리를 공유하기 때문에 별도의 기법없이 자원을 공유할 수 있다

3) 경제성 : Economy

프로세스를 생성할 때마다 프로세스를 위한 주소 공간이나 자원을 할당하면 cost가 굉장히 많이 발생하게 된다.
그러나 스레드는 자신이 속한 프로세스의 자원, 메모리를 자동적으로 공유하기 때문에 스레드를 생성해서 "context switch"하면 프로세스를 생성하고 "context switch"하는 것보다 더 경제적이다.

  • Thread : 프로세스의 메모리, 자원 등을 서로 공유
  • Process : OS로부터 자원을 독립적으로 할당받아서 사용

 

4) 규모 적응성 : Scalability

각 스레드가 서로 다른 CPU에서 병렬적으로 일을 수행하게 되면 더욱 더 효율적이고 속도 또한 훨씬 빨라질 것이다.


멀티코어 프로그래밍

멀티코어를 효율적으로 사용하고 병행성을 향상시키는 기법은 "다중 스레드 프로그래밍"이다
개발자는 멀티코어/멀티프로세서 시스템에 대해서 다양한 이슈들을 처리해야 한다

  • Dividing Activities
  • Balance
  • Data Splitting
  • Data Dependency
  • Tasting & Debugging

 

병행성? (Concurrency)

"프로그램의 성질"
- 둘 이상의 작업을 지원

- 싱글코어/싱글프로세서 스케줄러가 Concurrency를 제공한다

>> 여기서 둘 이상의 작업을 동시에 수행 가능하다면 "병렬성"을 가진다

 

병렬성? (Parallelism)

"기계의 성질"
- 둘 이상의 작업을 동시에 수행 가능

 

▶ Data 병렬성

동일한 데이터를 나누어서 각 코어에 분배하고, 각 코어는 동일한 연산을 각각 수행한다

▶ Task 병렬성

Task(스레드)를 각 코어에 분배하고, 각 스레드는 unique한 연산을 각각 수행한다

  • 각 스레드는 동일한 연산을 할 수도 있고, 서로 다른 연산을 할 수도 있다

 


다중 스레드 모델

user thread? kernel thread?

▶ user thread

라이브러리의 도움을 받는 스레드

- user space에서 동작
- user thread가 여러개 있다는 사실을 OS는 알지 못한다
- 따라서, user program이 각각의 user thread를 라이브러리의 지원을 통해서 관리해야 한다
- kernel의 입장에서는 user threads 각각을 일반적인 프로세스로 본다

  • POSIX pthreads, Window threads, Java threads, ....

 

▶ kernel thread

kernel의 도움을 받는 스레드

- kernel space에서 동작
- 스레드가 여러개 있다는 사실을 OS는 당연히 알고 있다
- thread간의 switching은 kernel이 "CPU Scheduling"하듯이 switching해준다

  • Window, Linux, UNIX, MacOS, ....

 

>> user space - kernel space간 Mapping 관계가 필요하다

 

1) 다대일 모델 : Many to One

여러개의 user thread를 하나의 kernel thread로 Mapping하는 모델이다

- 스레드 관리는 user space의 라이브러리에 의해 관리된다

  • Solaris Green Threads
  • GNU Portable Threads

 

※ 문제점

"One Thread Blocking causes all to block"

user threads 중 하나의 user thread가 "blocking I/O"를 호출하게 된다면
>> 하나의 kernel thread는 여러개의 user threads에 Mapping되어 있는데 "blocking I/O"에 대한 처리를 해주면 다른 user threads들이 kernel thread에게 어떠한 요청도 하지 못한다

한번에 하나의 user thread만 kernel thread에 접근할 수 있기 때문에 다중 스레드가 멀티코어 시스템에서 병렬로 실행될 수 없다

그리고 MultiThread는 MultiCore에서 병렬로 실행될 수 없다. 왜냐하면 한번에 user thread 하나만 kernel에 존재할 수 있기 때문이다

 

2) 일대일 모델 : One to One

각 user thread마다 kernel thread가 1:1로 Mapping된다
>> 다대일 모델에 비해 더 많은 병렬성을 제공할 수 있다

  • Windows
  • Linux
  • Solaris 9 and later

 

※ 문제점

user thread를 생성하면 그에 mapping되는데 kernel thread또한 생성되어야 하고 그리고 overhead때문에 제약이 발생할 수 있다

 

3) 다대다 모델 : Many to Many

여러개의 user thread들을 그보다 작거나 같은 수의 kernel thread로 다중화한다

  • kernel thread의 수는 user program이나 특정 기계에 따라 결정된다

다대일 모델은 많은 수의 user thread를 생성할 수 있지만 kernel thread는 하나만 생성할 수 있으므로 병렬적이지 못하다

일대일 모델은 많은 수의 user thread에 대한 1:1 mapping kernel thread를 생성할 수 있지만, 많은 수의 kernel thread가 시스템에 많은 부담을 주게된다

다대다 모델은 (다대일 모델, 일대일 모델)의 단점을 어느 정도 해결한 모델로써, 개발자는 많은 수의 user thread를 생성할 수 있고 그에 상응하는 kernel thread를 다중 코어에서 병렬로 수행할 수 있다

>> user thread가 "blocking I/O"를 호출할 경우, 다대일 모델은 다른 user threads들은 kernel thread에게 요청을 하지 못하는데 다대다 모델은 "blocking I/O"를 수행중인 kernel thread 이외의 kernel threads에게 요청을 할 수 있다

 

4) Two-Level Model : Many to Many + One to One

다대다 모델에 추가해서 하나의 user thread가 하나의 kernel thread로 mapping되는 것을 허용하는 모델이다
하지만 실제로 구현하기는 다대다 모델과 마찬가지로 굉장히 힘들다

  • IRIX
  • HP-UX
  • Tru64 UNIX
  • Solaris 8 and earlier

 

>> 현대 대부분의 시스템에서 CPU 코어가 증가하는 추세라서, kernel thread의 수를 제한하는 것의 중요성이 약해졌다. 따라서 현재 OS는 일대일 모델을 주로 사용한다