지난 포스팅에서 다룬 쓰레드 개념에 이어서 멀티쓰레드에 대해서 다뤄보겠습니다.
멀티쓰레드
멀티쓰레드는 말 그대로 쓰레드가 여러개 존재하는 것을 의미합니다. 의미는 굉장히 간단하니 넘어가기로 하고, 전에 다룬 멀티 프로스와 혼동될 수 있는 개념이므로, 한번 짚고 넘어가봅시다.
각 instruction은 점(.)을 의미했고, 그러한 점들이 모인 instruction set이 곧 thread라고 설명한 바 있습니다. 그러한 쓰레드들을 기준으로 용어들을 정리한 그림입니다.
즉! 여러 개의 쓰레드가 존재하는 것이 멀티쓰레드가 아니라 하나의 프로세스 내에서 여러 개의 쓰레드가 존재해야 멀티쓰레드인 것입니다.
멀티쓰레드! 왜 쓰는거죠??
그렇다면 우리는 멀티쓰레드를 왜 사용할까요?? 제가 이 개념을 처음 배우고 느낀 것은, '그냥 멀티프로세스 쓰면 안돼..?' 였습니다. 어리석은 질문이었지만요..
프로세스를 동시에 처리함을 결정하는 것은 프로세서의 수, 즉 CPU 코어의 수를 의미하므로 프로세스를 무작정 늘리는 것은 좋지 않습니다. 또한 프로세스간에 할당을 바꾸게 되면, 즉 프로세스 스위치를 진행하면 해당 과정에서 소요되는 시간도 무시할 수 없을 정도가 되겠죠.
이러한 연유로 우리는 멀티 쓰레드 개념을 사용합니다.
예시를 들어서, 조금 쉽게 설명해보려 합니다.
class Main{
public static void main(String args[]){
int x = 1;
input_handling(x);
y = tranforming(x);
output_handling(y);
}
int input_handling(int a){...}
int tranforming(int a){...}
int output_handling(int a){...}
}
이러한 자바 코드가 있다고 해봅시다.
그냥 단순히 세 개의 메서드를 순차적으로 실행하는 코드입니다. 이 때, 만약 하나의 메서드당 하나의 프로세스가 생성되는 시스템이라면 아래의 그림처럼 흘러갈 것입니다.
지난 글에서 IPC에 대해서 다뤘습니다. 간단히 말하면, 프로세스간에 통신하기 위한 수단입니다. 자세한 것은 이 글을 참고해주세요.
위 코드를 멀티쓰레드를 사용하지 않는다면, IPC를 이용해서 서로의 데이터를 송수신하는 과정이 필요할 것입니다. (예를 들면, main에 있는 변수 x에 대한 정보라던지..) 그렇다면 프로세스간의 전환이므로 프로세스 스위치 과정에 의해서 시간이 어느정도 소요되게 됩니다.
하지만 멀티쓰레드를 사용한다면 어떻게 될까요??
하나의 프로세스 안에서 진행되므로, IPC를 사용하지 않습니다. 즉, 프로세스 스위치가 일어나지 않죠. 그 대신 하나의 프로세스 내에서 Data 영역 등의 부분에서 서로의 변수 정보 등을 공유하게 됩니다. 각 메서드마다 자기의 변수 메모리를 갖고있지 않아도 되는 셈이죠.
따라서 시간적인 측면, 메모리 측면에서도 장점이 많아지게 됩니다.
그렇다면 쓰레드는 어디에서 생성될까요??
User-Level Thread
쓰레드는 User-Level Thread와 Kernel-Level Thread로 나뉩니다.
User-Level Thread는 쓰레드의 생성을 유저측에서 도맡습니다. 쓰레드 라이브러리를 통해서 쓰레드를 생성하고 관리하기 때문에, 커널에서는 쓰레드가 생성되었음을 감지하지 못합니다. 이에 대한 아주 큰 단점이 존재합니다.
바로 이러한 문제는 쓰레드가 Block되었을 때 나타납니다. 쓰레드는 TCB에서 state를 관리합니다.
쓰레드의 state는 TCB에서 관리됩니다. 그렇다면 PCB의 state는 무엇을 의미할까요?? 만약 프로세스 내부에 여러개의 쓰레드가 서로 다른 state를 갖는다면 PCB는 어떤 state를 갖게 될까요??
우선, 프로세스에서 최초로 존재하는 쓰레드의 state가 PCB의 state를 나타냅니다. 그래서 가장 최초의 쓰레드는 TCB에 state가 없습니다. PCB가 나타내고 있기 때문이죠. 이후, 쓰레드를 생성하게 되면 해당 쓰레드는 TCB에서 sate를 갖습니다.
만약 한 프로세스 내에서 특정 쓰레드가 block이 되었고, 이를 커널에게 알린다면 커널은 프로세스의 자원을 해당 프로세스 전체에 할당하지 않습니다.
그러니까, 하나의 쓰레드가 block되면 해당 프로세스 내에 있는 모든 쓰레드의 동작이 멈추게 되는 것이죠. 이는 꽤나 큰 단점으로 작용합니다.
Kernel-Level Thread
그러나 커널에서 생성되는 쓰레드는 커널이 인지합니다. 따라서, 각 쓰레드마다 다른 state를 가졌음에도 각 쓰레드에게 자원을 할당할 수 있습니다. 즉, 각 쓰레드의 state가 다른 쓰레드에게 영향을 미치지 않게 됩니다.
하지만, 커널에 쓰레드를 생성한다는 것은 프로세스가 커널 모드에 진입한다는 것을 의미하고 이는 Mode change를 해야한다는 것을 의미하죠. 따라서, mode change에 시간이 소요된다는 것을 알 수 있습니다.
+) Kernel-Level Thread에서는 커널이 쓰레드를 생성하고 TCB의 정보만을 user에게 전달해줍니다.
User-Level Thread v.s Kernel-Level Thread v.s Process
실제, User, Kernel, Process로 처리할 때의 시간 소요를 측정한 결과입니다.
User-Level은 Fork() 즉, 쓰레드를 만드는데 34가 걸린다고 하면, Kernel-Level은 948이 걸립니다.
Kernel-mode에서 단지 mode change가 2번 일어난 것인데, 왜이렇게 시간 차이가 많이 나는지 의문이 가실 수 있습니다.
사실 이는, 커널 모드에 진입했을 때 수행하는 일련의 과정을 알면 조금 더 이해하기 쉽습니다.
커널 모드에 진입하게 되면, 커널에게 부탁한 일(ex. 쓰레드 생성)만을 진행하는 것이 아닙니다. 커널 모드에 진입하게 되면, 그 외에 몇가지 일들을 더 처리하게 되는데 이는 이후에 다룰 것이므로.. 아! 이런 연유로 시간이 오래 걸리는구나!!만 이해하고 넘어갑시다.
또한 프로세스 딴에서 처리하는 것은 프로세스 스위치 과정과 더불어 쓰레드를 생성하는데 걸리는 시간보다 프로세스를 생성하는데 걸리는 시간이 더욱 크므로, 이러한 시간 차이는 납득이 되리라 생각합니다.
오늘은 이렇게 멀티 쓰레드에 대한 개념을 다뤄봤습니다. 감사합니다.
'CS > OS' 카테고리의 다른 글
[운영체제] 5-2. Race Condition (0) | 2023.10.03 |
---|---|
[운영체제] 5-1. 프로세스 동기화 (0) | 2023.10.02 |
[운영체제] 4-2. 쓰레드 정의 (0) | 2023.09.27 |
[운영체제] 4-1. 프로세스 종료, IPC (0) | 2023.09.27 |
[운영체제] 3-3. 프로세스 스위치 (0) | 2023.09.23 |