센로그

4. Therad & Concurrency 본문

CS/운영체제

4. Therad & Concurrency

seeyoun 2023. 9. 18. 14:33

◆ Thread

프로세스 내에서 실행되는 작업의 최소 단위

여러개의 작업을 동시에 처리하고자 할 때 스레드를 사용함.

 

하나의 프로세스가 동시에 한 작업만 수행하는 것을 싱글 스레드,

하나의 프로세스가 동시에 여러 작업을 수행하는 것을 멀티 스레드라고 한다.

 

하나의 스레드는 무조건 하나의 코어에서만 돌아간다.

 

 

ex)

스레드 동작 예시

 

싱글스레드의 경우, task1이 끝나고 나서 task2를 돌림.

멀티스레드의 경우, task1task2가 동시에 작동함 

 


◆ Thread 구성요소

스레드는 다음 요소들을 개별적으로 갖고 있다.

  • Thread ID - 각자의 식별자
  • Program Counter - 각자의 진행 흐름 표시해야 하기 때문
  • Register Set
  • (메모리의) Stack 영역 - 어떤 함수를 호출하는지가 다르기 때문

 

그리고 다음 요소들은 서로 공유한다.

  • Code(text) 영역
  • Data 영역
  • Heap 영역
  • Open files
  • Signals 

 

 

이해하기 쉽게 다음 그림을 보자.

각 스레드는 개별적인 stack을 갖고 있다고 했다. 

오른쪽 그림과 같이, 프로세스 메모리 공간에 stack이 여러개 생기는 구조이다. (각 스레드별 stack)

 

각 스레드는 모두 data, heap, text에 접근할 수 있으므로, static이나 global 변수 같은 거 접근 가능한 뜻임.

만약 한 스레드가 글로벌 변수++하면, 다른 스레드가 접근했을 때도 ++된 걸로 나온다는 뜻

 

※ 프로세스와 스레드의 가장 큰 차이점은 공유하는 데이터 공간의 유무이다.
한 프로세스에서 비롯된 스레드들이더라도 자신만의 스택, 레지스터 값, PC값을 갖고있어서 아예 따로 실행 가능하다.

 


◆ Thread 장점

왜 스레드를 쓰는지에 관한 이야기.

  • Responsiveness(응답성) - 실행 흐름이 나뉘어져 있으므로, 프로세스의 일부가 block되어도 나머지는 계속 실행 가능하다.
  • Resource Sharing(자원 공유) - 스레드 사이에서는 데이터 공유가 쉽다. (글로벌 변수 두고 그걸로 하면 되니까)
  • Economy(경제성) - 프로세스 만드는거보다 스레드 만드는게 더 비용이 적게 든다. (한 메모리 공간을 공유하고, 일부 리소스들도 공유하기 때문)
    스레드 스위칭 역시 컨텍스트 스위칭에 비해 오버헤드가 적다. 
  • Scalability(확장성) - 각 스레드가 각기 다른 프로세서에서 실행할 수 있기 때문에, 멀티 코어 구조에서 극대화된 이득을 가질 수 있다. (싱글 스레드로 하면, 코어가 몇 개이이든 간에 프로세스가 코어 한 개에서만 돌음. 남는 코어 많아도 이득을 못 봄)

 


◆ Parallelism vs Concurrency

  • Parallelism: 두 개 이상의 코어에서 task들이 실제로 동시에 돌아가는 것
  • Concurrency:  task들이 동시에 돌아가는 것 처럼 보이는 것

 

Tn 은 n번 task를 의미.

 

위 그림처럼 하나의 코어가 여러 스레드를 번갈아가면서 수행함으로써, 동시에 실행되는 것처럼 보이게 할 수 있다. (Concurrent)

아래에서는 여러 개의 코어가 각 스레드를 실제로 동시에 수행하는 방식이다. (Parallel)

 

Hyperthreading: Parallelism하는게 아니라 Hardware가 context Swtching처럼 thread 빠르게 전환 하는 것.

 


◆ Parallelism

Parallelism에는 두가지 종류가 있다

  • Data parallelism : 하는 작업은 똑같은데, 데이터만 분담해서 처리하는 것.
    ex) 많은 데이터들을 GPU에 때려 넣어서 병렬 처리(계산)하는 것.
  • Task parallelism : 각각 하는 작업이 다른 것. 작업을 분담한 것. 데이터는 공유해서 쓰지만 패스별로 나누어서 사용

 


 Multicore Processing

하나의 작업을 위해 여러 개의 CPU 코어를 사용하는 것

 

원래는 CPU 코어가 하나밖에 없었고 코어 자체의 성능을 발전시키고자 노력했는데,

계속 기술이 발전하다보니 한 코어로 처리할 수 있는 스피드의 HW적 한계에 도달하게 됨.

→ CPU에 여러 개의 코어를 넣어서 동시에 많은 처리하자!

 

멀티 코어에 멀티 스레딩을 구현 하는 건 프로그래머의 몫임.
코어가 여러 개 있다는 걸 인지하고 구현하지 못하면 하드웨어를 최대한 활용하지 못하는 것

따라서 이건 멀티 스레딩으로 구현할 수 있어! 라고 한다면, 그렇게 하는게 성능적으로 좋다.

스레드 라이브러리 예시) POSIX Pthreads, Windows threads, Java threads

 

물론, 그만큼 주의해야할 사항들이 있다.
  • Identifying tasks : 각 task들을 parallel하게 실행하려면 서로 독립적이여야 한다.
  • Balance : 각 task들의 size, runtime 등이 비슷해야 한다.
  • Data splitting : Application이 여러 task로 나뉘는 것처럼 data역시 task에 따라 분할되어야 한다.
  • Data dependency : 서로 다른 task가 같은 data를 read/write한다면 dependency가 생기게 되는데 이 때 synchronizaion을 해주어야 한다.
  • Testing and debugging : Single-threaded에서는 execution path가 매우 단순하지만 multi-threaded에서는 그렇지 않다. 작은 변화에도 execution path가 달라지기 때문에 test/debugging이 매우 어렵다.

 

< Amdahl's Law >

암달의 법칙 : 병렬 처리시 최대 어느정도의 성능 향상이 가능한지 계산하는 법칙.

S는 무조건 연속적으로 실행해야 하는 부분을, N코어의 개수를 의미한다.

 

 

ex)

원래 하나의 코어에서 실행하던 걸 두 개에서 실행한다고 하자.

무조건 연속적으로 실행해야 하는 부분이 25%라면, 다음과 같이 계산할 수 있다.1/(0.25+0.75/2) ≒ 1.6→ 실행 속도는 최대 1.6배까지 빨라질 수 있다는 의미이다.

 

어느 정도 최적화하느냐에 따라 우리가 얻을 수 있는 스피드가 달라진다.

따라서 프로그램 전체를 대상으로 최적화하느 것이 중요하다.

 

Ideal speedup: 전부 병렬화 가능한 경우를 의미함.

S의 비율이 늘어날수록, 코어가 늘어나도 speedup은 별로 안 늘어난다.

 


 User thread vs Kernel thread

  • User thread : 유저 레벨의 스레드 라이브러리가 관리하는 스레드
    유저 스레드는 실행되기 위해서는 반드시 OS 스레드와 연결이 되어야 함.
    이유는, CPU에서 실행되는 단위는 OS 스레드이기 때문.
    장점 :
    • OS 입장에서는 신경을 안 써도 되니 오버헤드가 적다
    단점 :
    • 안정성이 떨어진다.
    • 한 프로세스 안에 1, 2, 3 스레드 3개가 있는데 만약 3번 스레드가 커널에게 trap을 걸어 I/O요청을 했을 때 3번 스레드 뿐만 아니라 1~3 스레드 전부가 waiting queue에 들어가게 된다. (프로세스 단위로 CPU가 할당되기 때문)

 

  • Kernel thread : 커널이 지원하는 스레드. 최신 OS들은 대부분 커널 스레드를 지원한다.
    장점 :
    • 기능상 커널에서 관리 하는 것이 더 신뢰성 있고 안정적
    • 진정한 의미의 멀티스레드
    단점 :
    • 유저 모드에서 커널 모드로 계속 바꿔줘야 하기 때문에 성능이 저하

 


Multithreading Models

유저 스레드들과 커널 스레드들 사이에 관계가 생길 것인데, 이 관계에 따라 다음과 같이 멀티스레딩 모델을 분류한다.

 

[user]-to-[kernel]

  • Many-to-One 모델
    : 유저 스레드 여러 개가 커널 스레드 하나에 매핑되는 모델

    - 한 스레드가 갑자기 block 되면, 커널 스레드 자체가 block 될 것. 
    - 한 번에 하나의 유저 스레드만 커널에 접근할 수 있기 때문에, 멀티코어 시스템에서 병렬적인 수행을 할 수가 없다.

  • One-to-One 모델
    : 유저 스레드 하나가 커널 스레드 하나에 매핑되는 모델
    - 대부분 이 방식을 사용한다. 대표적으로 Windows와 Linux에서도 사용함.
    - 멀티코어 시스템에서 동시에 여러 스레드를 수행할 수 있도록 해준다.
    - 그러나 유저 스레드를 늘림에 따라 커널 스레드도 똑같이 늘어나는데, 커널 스레드를 생성한다는 것은 오버헤드가 큰 작업이므로 성능 저하가 발생한다. (스레드 개수 제한 등의 방식이 필요하다)

  • Many-to-Many 모델
    : 여러 유저 스레드에 더 적거나 같은 수의 커널 스레드가 대응하는 모델

    - 비교적 자유도가 높으나, 구현하기 복잡하다. 

 


Thread Libraries

실제로 스레드를 만들 때는 스레드 라이브러리를 이용한다.

이때 유저 레벨 라이브러리를 사용하거나, 커널 레벨 라이브러리를 사용할 수 있다.

 

 

스레드 라이브러리 예시) 

■ Pthread

: POSIX 스탠다드를 따르는 스레드 라이브러리.

 

■ Pthread 사용 예시

 

■ Pthread - 스레드 취소 (스레드 강제종료)

취소 모드에 따라 스레드의 취소 요청을 어떠한 시점에 처리할지를 결정하게 된다.

지연 취소(Deferred cancellation) 
: 기본값. 시스템상에서 해당 스레드의 다음 취소 시점(Cancellation point)까지 대기
- pthread_cond_wait(), pthread_join() 그리고 pthread_testcancel() 과 같은 함수가 취소 시점을 제공하므로 해당 함수 호출 때까지 대기
- 시스템 마다 지원하는 취소 시점(Cancellation point)이 상이 하므로 원하는 취소 동작을 수행할 수 있는지 확인 필요

 

비동기 취소(Asynchronous cancellation) 
: 취소 요청시 즉시 처리 시도(지연 가능성 있음)

 

 

또는 취소 절차를 허용하지 않도록 설정할 수도 있다.

 

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

6. Synchronization Tools  (0) 2023.10.14
5. CPU Scheduling  (0) 2023.09.20
3. Processes  (0) 2023.09.13
2. Operating System Structures  (0) 2023.09.06
1. OS overview  (0) 2023.09.04
Comments