관리 메뉴

JIE0025

멀티스레딩의 개요 및 운영체제 기초 본문

개발/Java, Kotlin

멀티스레딩의 개요 및 운영체제 기초

Kangjieun11 2023. 8. 6. 17:06
728x90

 

 

✅ 멀티스레딩은 왜 필요할까?

 

2가지 (응답성, 성능)를 위해서이다.

 

 

1. 응답성

 

만약 수천명이 사용하는 온라인 마켓 Web Application이 있다고 가정해보자.

모든 사용자의 구매정보를 DB에 저장하는데,

한 고객이 여러개의 물건을 구매했다 . -> DB 실행 시간이 길어진다.

이때 동시에 다른 고객도 구매를 하고 싶어하면? 

 

앱이 첫번째 요청에 응답할때까지

두번째 요청자는 대기 하게 된다.

 

 

이것이 멀티스레딩의 첫번째 필요성이다.

 

각 스레드는 각 요청을 처리하도록 하여

사용자의 대기시간을 줄이며 응답성을 높힐 수 있다.

 

 

우리는 크롬과 같이 여러개의 창을 띄어둔 채로 컴퓨터를 한다. 

이때 모든 작업이 마치 동시에 실행되고 있는것처럼 생각하게 되는데

 

이 또한 멀티스레딩을 이용한 것이고, <병행성>이라고 한다. 

 

 

2. 성능

병행성을 이용헀을 때 하나의 코어만으로도 여러 작업이 동시에 수행되는 듯한 효과를 누릴 수 있다.

코어가 늘어나면 늘어날수록 점점 더 복잡한 작업을 동시에 수행할 수도있다.

 

싱글 스레드를 사용하는 것보다 

같은 시간 안에 더 많은 작업을 수행할수도 있다. 

 

 

 

✅ OS, 프로세스, 스레드의 관계성

 

컴퓨터를 실행시키면 어떤 일이 발생하는지 과정을 통해

OS, 프로세스, 스레드에 대하여 간단하게 알아보자.

 

 

1)  컴퓨터를 키면  OS(운영체제)라는 프로그램이  디스크에서 메모리로 로드된다. 

 

2) OS는 우리를 대신해 HW, CPU사이의 상호작용을 돕는다. (개발자가 개발에만 집중할 수 있게 된다)

 

3) 애플리케이션은 디스크에 저장되어있다.

 

4) 사용자가 애플리케이션을 실행하면 OS는 디스크에 있던 프로그램을 메모리로 가져온다.

이후 프로그램의 인스턴스를 생성한다.

* 인스턴스 : Process  or  Application Context

 

 

5) 각 프로세스 안에는 아래와 같은 메타데이터가 존재한다. 

 

* 모든 스레드가 공유하는 공간

* 각 스레드마다 고유의 공간

 

- PID : 애플리케이션 Read/Write를 위한 ID

- Code : CPU에서 실행되는 명령어들

- Heap : 애플리케이션에 필요한 데이터들이 존재하는 공간

 

- Main Thread : 동작을 위한 기본적인 스레드 

스레드별로  Stack(지역변수 저장),  Instrction pointer(스레드가 실행할 다음 명령어의 주소)가 존재한다. 

 

 

 

** 각각의 스레드는 

순간마다 서로 다른 함수를 이용하며 다르게 동작하기 때문에 

스레드별로 Stack과 Instruction Pointer가 따로 존재하는것이다.

 

 

 

✅ Context Switching

 

컨텍스트 스위칭이란? 

 

각 인스턴스는 독립적으로 실행되며 1개 이상의 스레드를 갖고 있다. 

이때 모든 스레드들은 CPU실행을 두고 서로 경쟁한다. 

 

 


Example

- 만약 프로그램 3개가 동시에 실행되고 있다고 가정하자.

 

프로세스 1) 크롬

- 스레드1은 블로그를 작성중이다.

- 스레드2는 구글링을 하고 있다.

 

프로세스 2) 카카오톡 

- 스레드1은 단체 채팅방을 사용중이다.

- 스레드2는 친구와 카톡을 한다. 

- 스레드3은 나와의 채팅방에 정보를 저장한다.

 

프로세스 3) PDF 앱 

- 스레드1은 한개의 문서를 열어두었다.

 

여기에 존재하는 모든 스레드들은 CPU 실행에 있어 경쟁을 한다.


 

 

코어가 2개라고 가정하면, 스레드는 코어보다 더 많아질 것이다.

 

운영체제는 스레드 하나를 실행하고 멈추고 다른 스레드 하나를 실행하고 멈추는 작업을 반복한다.

이것을 Context Switch라고 한다.

 

 

Context Switch에는 비용이 드는데, 이게 아주 비싼 작업이다. 

 

- CPU에서 실행되는 스레드 CPU내부 레지스터, 캐시, 메모리내의 커널 리소스 같은것들을 차지한다.

- 스위칭 작업에서는 기존 스레드에서 사용하던 모든 데이터를 저장하고 복원하는 과정이 필요하다. 

 

 

결국 동시에 너무 많은 스레드를 다루면 효율성이 떨어지게 된다.

 

 

* Thrashing : OS가 너무 많은 일로 생산적이지 못하고, 컨텍스트 스위칭에 더 많은 시간을 할애하는것

 

 

 

✅ Thread Scheduling

OS의 선택기준을 알아보자.

 

어떤 스레드를 실행하고, 언제 Context Switch를 할까? 

 

스레드 스케쥴링이란 이런 선택의 기준이 된다.

 

 

 

아래와 같은 상황을 보자.


⏺ 뮤직플레이어 :

UI (마우스/키보드에 반응), 음악 송출

 

메모장

UI (마우스/키보드에 반응) , File 자동 저장 (2초에 한번씩 저장)

 


 

작업의 도착순서 및 실행 시간이 주어질 때 누구를 먼저 실행해야할까?

 

 

1) FCFS (FIFO) : 선입선출

First Come Fisrt Serve

먼저 도착하는 작업이 먼저 실행된다

 

문제점 : 실행시간이 긴 스레드가 먼저 도착하게 될 경우 다른 스레드에 기아 현상이 발생한다. 

 

 

>> UI 스레드에 기아 현상이 발생하게 되면 Application의 응답성을 방해하게 되고 최악의 사용자 경험이 된다. 

음악송출 스레드가 3분, UI가 1초라고 가정하면, 사용자는 한번 클릭에 대한 반응을 3분 1초에 경험하게 됨..

 

 

2) SJF : 짧은 작업 먼저

Shortest Job First

 

문제점 : 긴 작업들은 영원히 실행될 수 없다.

사용자 관련 이벤트가 항상 시스템에 존재하게 된다.

 

사용자가 계속 UI를 클릭하게 되면 짧은 작업들의 우선순위가 높아서 긴 작업들은 시스템에 존재할 수 없다.

 


 

3) Epochs

 

일반적인 OS의 스케줄링 방법은 Epoch를 이용한다.

 

OS는 Epoch 에 맞추어 시간을 적당한 크기로 나눈다.

* Epoch는 하나의 시간 단위라고 생각하면 편하다.

 

Epoch1 -> Epoch2 -> ....

 

 

스레드의 종류별로 1개의 Epoch에 시간을 할당하고, 

스레드 중 남은것들이 있으면 다음 Epoch에 시간을 할당해주는 느낌이다.

 

 

⏺ 스레드에 시간을 할당하는 방법 :

동적 우선순위 = 정적 우선순위 + Bonus

 

- OS가 각 스레드에 적용하는 동적 우선순위에 달려 있음.

- 정적 우선순위는 개발자가 미리 설정

- Bonus : OS가 각 Epoch마다 조절함

 

OS는 즉각적이거나 사용자 interactive한 스레드에 우선순위를 주면서도

기아 현상을 막기 위해 이전 Epoch에서 실행시간이 부족하거나 완료되지 않은 스레드도 체크하게 된다. 

 

 

✅ 멀티스레드와 멀티프로세스

멀티스레드는 언제 사용하고

멀티프로세스는 언제 사용할까?

 

✍️ 멀티스레드 아키텍처

스레드는 많은 리소스를 공유하므로, 같은 데이터에 접근하고자 하는 경우 멀티스레드 아키텍처를 사용하면된다.(스레드는 생성과 파기가 빠르고, 같은 프로세스 내에서 스레드끼리의 전환이 쉽다는 장점이 있다)

 

 

✍️ 멀티프로세스 아키텍처

독립된 프로그램을 독립된 프로세스에서 실행하는게 좋은 경우도 있다. (보안, 안정성이 중요한경우)

 

 

 


 

 

오늘은 간단하게 멀티스레드와 OS관련 개념을 다시 훑어보았다.

다음부터는 실습도 함께 하며 글을 적어야지

!

 

 

references

더보기

Udemy