반응형

1.컨텍스트 스위칭(Context Switching) 이란?

컨텍스트 스위칭이란, 'CPU/코어에서 실행 중이던 프로세스/스레드가 다른 프로세스/스레드로 교체되는 것' 이다.

기본적으로 1개의 프로세스는 1개의 스레드를 가진다. 왜냐면 스레드가 CPU/코어에서 실행되는 기본 단위이기 때문이다.
프로세스가 다른 프로세스로 교체 된다는 것은, 프로세스 안에 실행되는 스레드가 다른 프로세스 안의 스레드로 바뀐다는 말이다.

여기서 말하는 컨텍스트란 프로세스/스레드의 상태를 의미합니다. 또 이 상태라는 것은 CPU, 메모리에서의 상태를 의미한다.

 

2. 컨텍스트 스위칭이 필요한 이유?

  • 여러 프로세스와 스레드들을 동시에 실행시키기 위해(그렇게 보이기 위해)
  • 여러 프로세스와 스레드들이 공정하게 CPU 시간을 나눠 갖기 위해
  • 높은 우선순위의 작업이 빠르게 처리될 수 있게

와 같은 이유가 있다.

 

3.컨텍스트 스위칭이 발생하는 이유

컨텍스트 스위칭은 운영 체제의 스케쥴러에 의해 관리된다.

스케쥴러는 다음과 같은 상황에서 컨텍스트 스위칭을 발생시킨다.

  • 실행 중인 프로세스가 주어진 Time Slice(Time Quantum)를 다 사용함.(할당된 시간을 모두 사용했을 때)
  • 실행 중인 프로세스가 I/O 작업을 요청하고, 결과를 기다리는 동안 다른 작업을 수행할 수 있을 때.
  • 다른 리소스를 기다려야 할 때.
  • 인터럽트(Interrupt)

 

 

위 사진에서 Time Quantum 동안 프로세스 1,2가 번갈아가면서 실행되고 있다.

매우 짧은 시간 동안 번갈아가면서 실행되기에 동시에 실행되는 것처럼 보이게 된다.

이렇게 프로세스가 바뀌는 것을 컨텍스트 스위칭이라고 한다.

 

5. 컨텍스트 스위칭은 누구에 의해 실행되는가?

OS의 커널(Kernel)(스케줄러)에 의해서 수행된다.

커널이란, 운영체제 중 항상 메모리에 올라가 있는 운영체제의 핵심 부분으로써 하드웨어와 응용 프로그램 사이에서 인터페이스를 제공하는 역할을 하며 컴퓨터 자원들을 관리하는 역할을 한다. 즉, 커널은 인터페이스로써 응용 프로그램 수행에 필요한 여러가지 서비스를 제공하고, 여러가지 하드웨어(CPU, 메모리) 등의 리소스를 관리하는 역할을 한다.

스케쥴러 : 어떤 프로세스에게 자원을 할당할지 순서와 방법을 결정하는 운영체제 커널의 모듈을 지칭한다.

 

6. 컨텍스트 스위칭이 일어나는 과정

컨텍스트 스위칭이 구체적으로 일어나는 과정은, 
다른 프로세스끼리의 스위칭(Process Context Switching)인지
같은 프로세스의 스레드들끼리의 스위칭(Thread Context Switching)인지에 따라 다르다. 
이 두 가지의 공통점과 차이점을 알아보자.

 

Process Context Switching과 Thread Context Switching의 공통점

1. 커널 모드에서 실행된다.

두 스위칭은 모두 커널 모드에서 실행된다.

커널 모드라는 말은, 어느 프로세스가 실행되다가 하드웨어와 밀접한 일들 혹은 컴퓨터에 있는 여러 리소스들을 다뤄야 하는 상황이 발생하면 프로세스가 직접 컴퓨터의 리소스에 접근하는 것이 아니라 운영체제를 통해 접근하게 된다.
이때, 이 프로세스에서 커널로 통제권이 넘어가서 커널에 의해서 실행되는 것을 '커널 모드'라고 합니다.

 

 

2. CPU의 레지스터 상태를 교체

두 스위칭은 CPU의 레지스터 상태를 교체한다.

레지스터에 대해서 간단하게 설명하고 가자면, 레지스터란 CPU에서 각종 명령어들을 수행하기 위해 필요한 여러 데이터들을 저장하는 곳이다. 많은 레지스터들이 있지만, 대표적으로 PC(Program Counter), Stack Pointer 등이 있다.

 

어떤 프로세스가 CPU에서 실행되고 있을 동안에, 레지스터에 있는 여러 값들이 계속 바뀌면서 실행되고 있었을 것이다. 이때, 프로세스B가 실행되면 실행되고 있던 프로세스A의 레지스터 상태들을 어딘가에 저장을 하고 프로세스B가 실행되는 것이다.

그래야 다시 프로세스A가 실행됐을 때 그때의 상태 정보들을 알고 있어야 이어서 실행할 수 있기 때문이다.

 

 

Process Context Switching

다른 프로세스끼리의 스위칭인 프로세스 컨텍스트 스위칭은 가상 메모리 주소 관련 처리를 추가로 수행한다.

 

1.MMU(Memory Management Unit)이 새로운 프로세스의 주소 체계를 바라보도록 수정
2.캐시 역할을 하는 TLB(Translation Lookaside Buffer)를 완전히 비워줘야 함.

 

MMU는 가상 메모리와 물리 메모리 사이의 주소 변환을 담당한다. 프로세스가 물리 메모리에서 할당되는 위치를 추상화하여 각 프로세스가 독립적인 주소 공간을 가지고 있는 것처럼 만든다.

TLB는 MMU 내에 존재하는 캐시 메모리이다. 가상 주소를 물리 주소로 변환하는 과정을 상대적으로 느릴 수 있기 때문에, 이러한 변환의 결과를 TLB에 저장해 두고 빠르게 사용하는 데에 목적이 있다.

 

스레드 간의 스위칭에서는 실행되고 있던 스레드의 상태를 저장하고, 새로 실행될 스레드의 상태를 로딩하는 것으로 해결이 되지만 프로세스간의 스위칭에서는, 위의 작업에 더불어서 MMU가 실행 될 작업의 메모리를 보도록 해야 하고 캐시 역할을 하는 TLB를 완전히 비워줘야 한다.

Thread Context Switching

같은 프로세스에 속한 스레드들끼리는 공유하는 메모리 지역이 있다.

코드(Code) 영역 : 프로세스가 실행할 코드
데이터(Data) 영역 : 전역 변수가 정적 변수들이 저장되는 영역
힙(Heap) 영역 : 동적으로 할당된 메모리
위 영역을 공유한다.

따라서 스레드들끼리의 컨텍스트 스위칭은 같은 프로세스에 속하기 때문에 스위칭이 일어나도 메모리와 관련해서는 챙겨줘야 할 부분이 없다.

 

즉, Process Context Switching과 달리 추가적인 작업 없이 위에서 서술한 커널모드 전환 + CPU register 상태교체 등 기본 작업만 하면된다. 그래서  Process Context Switching 보다 빠르다.

 

7. 컨텍스트 스위칭이 미치는 영향

컨텍스트 스위칭이 발생하면서, 캐시 오염(Cache Pollution)이라는 간접적인 영향이 발생한다.

 

캐시란 데이터나 값을 임시 저장해 두는 임시 장소이다. CPU가 자주 사용하는 것들에 대해서 매번 메모리에 접근하는 것이 아니라, 캐시에 저장해 두고 빠르게 데이터를 가져오기 위해 사용한다.

 

컨텍스트 스위칭이 일어나면, 또 사용할 것이라고 예상을 하고 캐시에 데이터나 값을 저장한 캐시가 의미가 없는 데이터가 되어버린다. 컨텍스트 스위칭이 일어난 직후에 캐시에 가봤자, 이전에 프로세스에서 실행되었던 정보들을 저장해놓고 있을 가능성이 매우 높기 때문에, 내가 필요한 정보는 없을 가능성이 매우 높아지기 때문이다.
그래서 메모리에 직접 접근하는 성능적으로 손해를 보는 부분이 발생한다.

 

8. 컨텍스트 스위칭과 스케줄링

스케줄링(Schedueling) 이란?

운영체제에서 의미하는 스케줄링은 운영체제가 CPU의 자원을 어떤 프로세스에게 할당해 줄 것인지 그 일정을 짜는것이다. Context Switching에는 많은 자원이 소모되므로, 이 일정을 어떻게 짰는지에 따라 CPU자원 사용의 효율성이 결정된다.

  • CPU를 사용하려고 하는 프로세스들 사이의 우선순위를 관리하는 작업 - 자원을 어떤 프로세스에 얼마나 할당하는지 정책을 만드는 것.

  • 프로세스들에게 자원을 최대한 공평하게 배분하며 처리율과 CPU 이용률을 증가시키고, 오버헤드, 응답시간(Response time / Turnaround time), 대기시간을 최소화하기 위한 기법

  • 선점형 스케줄링(Preemptive Scheduling) 과 비선점형 스케줄링(Non-preemptive / Cooperative Scheduling) 이 있음

  • 메모리에 여러 개의 프로세스를 올려놓고(다중 프로그래밍), CPU의 가동시간을 적절히 나누어(시분할) 각각의 프로세스에게 분배하여 실행

 

CPU 스케줄링이 발생하는 상황

  1. 실행 상태에 있던 프로세스가 I/O 요청 등에 의해 Block 상태가 되는 경우
  2. 실행 상태에 있던 프로세스가 타이머 인터럽트 발생에 의해 준비 상태로 되는 경우
  3. I/O 요청으로 Block 상태에 있던 프로세스의 I/O 작업이 완료되어 인터럽트가 발생하고, 그 결과 이 프로세스의 상태가 준비 상태로 바뀌는 경우
  4. CPU에서 실행 상태에 있는 프로세스가 종료되는 경우
[참고] 프로세스의 생명주기



-생성 (Create) : 프로세스 생성

-실행 (Running) : 프로세스가 프로세서를 차지하여 명령어들을 실행

-준비 (Ready) : 프로세스가 프로세서를 사용하고 있지는 않지만 언제든지 사용할 수 있는 상태로, CPU가 할당되기를 기다리는 중

-대기 (Waiting) : 프로세스가 입출력 완료, 시그널 수신 등 어떤 사건을 기다리고 있는 상태

-종료 (Terminated) : 프로세스 종료

 

 

Context Switching 에서의 Context

위에서 서술했듯이 CPU가 프로세스를 실행하기 위한, 프로세스에 대한 정보를 의미한다.

그 정보로는 현재 프로세스의 상태, 프로세스가 다음에 실행할 명령어, 레지스터 값, 프로세스 번호 등이다.

멀티프로세스 환경에서는 여러 프로세스가 동시에 실행되는 것처럼 보이기 위해 노력중이다. 그 노력의 일환인 프로세스간 CPU 자원 할당 이동이 Context Switching 이며, CPU는 기존 할당된 프로세스의 Context를 저장하고, 새로 자원을 할당할 프로세스의 Context로 교체하는 과정을 거쳐 새로운 프로세스에게 자원을 할당한다.
주의 할 점이 있는데 Context Switching 중에는 CPU는 아무 일도 하지 못 한다. 

프로세스에 의해 CPU 자원이 점유되고는 있지만, Context Switching중이기 때문에 실제로 사용되는 프로세스가 없다는 것이고, 이 말은 즉, Context Switching이 너무 자주 발생하면 CPU의 성능이 떨어지게 되는 것이다.

CPU의 성능이 떨어지지 않게 필요한 순간에 적절하게 Context Switching이 발생하도록 하는 알고리즘이 필요하며, 

이 알고리즘을 사용하는 주체가 바로 운영체제 스케줄러다.
스케줄러는 우선순위가 가장 높은 프로세스에게 CPU 자원을 할당 해 준다. 그렇다면 이 우선순위는 어떻게 결정될까?

프로세스 스케줄링 방식에 따라 OS를 크게 두 가지 방식으로 나눌 수 있다.

 

1) 비선점형(Non-Preemptive) OS

 

비선점형 OS는 현재 실행 중인 프로세스보다 높은 우선순위를 가지는 프로세스가 실행된다고 해서 실행 대상을 바로 변경하지 않는다.
새로 실행된 보다 높은 우선순위의 프로세스가 실행되기 위해서는 현재 실행 중인 프로세스가 명시적으로 CPU를 양보할 때까지, 혹은 I/O 작업 등으로 블로킹 상태가 될 때까지 기다려야만 한다.

과거 Windows95 이전, 그리고 Mac OS X 이전의 OS들이 비선점형 OS 였으며, 그 이후의 모든 OS는 선점형 OS 이다.

  • 특정 프로세스가 CPU 를 독점하는것이 가능 (프로세스가 스스로 CPU 점유를 포기해야만 다른 프로세스가 실행)


비선점 스케줄링

 

FCFS (First Come First Service)
프로세스가 Ready Queue에 도착한 순서대로 CPU에 할당하는 방식이다. 작업 완료 시간을 예측할 수 있지만, 위에서 언급했듯이 급하게 처리해야 하면서 짧은 처리 시간을 가진 작업이 자기 순서를 한참 기다려야 할 수도 있다. 이러한 상황을 Convoy Effect, 호위 상태라고 한다.

SJF (Shortest Job First)
프로세스를 CPU 처리 시간이 짧은 순서대로 CPU에 할당하는 방식이다. 모든 방식을 통틀어 평균 대기 시간을 가장 짧게 만드는 방식으로 알려져 있다. 그러나 CPU 처리 시간이 긴 프로세스는 뒤로, 뒤로 계속 밀려난다. 자기 순서가 오지 않는 상황이 발생 할 수도 있다. 이러한 상황을 기아 상태라고 한다.

HRN (Highest Response Ratio Next)
SJF 방식에서 발생할 수 있는 기아 상태를 해결하기 위한 방식이다. 우선순위 처리를 단순 CPU 처리시간이 아닌, Ready Queue 에서 대기한 시간까지 고려해서 결정한다.
((대기 시간 + CPU 처리 시간) / CPU 처리 시간)
기다린 시간에 비례하여 우선순위를 높이는 방식으로 에이징 기법이라고 한다.

HRN이 이상적인 방식으로 보이고 FCFS 를 사용할 이유가 없어 보이지만 실제로는 SJF 나 HRN 을 사용하기 어렵다. 현실적으로는 프로세스마다 CPU 처리 시간이 얼마나 걸릴지 알 방법이 없다.

 



2) 선점형(Preemptive) OS

 

선점형 OS는 실행 중인 프로세스보다 높은 우선 순위의 프로세스가 실행되면, 스케쥴러에 의해 실행 순서가 적극 조정되는 OS를 얘기한다.

또한, 비선점형 OS에 비해 훨씬 더 스케쥴링이 복잡하게 처리가 되어 있는데, 우선 순위가 같은 프로세스들간 실행 배분에도 관여를 하기 때문이다.


최근의 모든 OS는 선점형 OS이다.

  • 특정 프로세스가 CPU 를 독점하는것이 불가능(운영체제가 강제로 프로세스의 CPU 점유를 제어)

 

선점 스케줄링

 

SRT (Shortest Remaining Time)
SJF 방식을 선점 스케줄링 방식으로 변경 한 기법이다. SJF 와 동일해 보이지만 선점 방식이기 때문에 CPU를 점유중인 프로세스보다 남은 CPU 처리 시간이 짧은 프로세스가 Ready Queue에 들어올 경우에는 CPU 점유를 뺏어버릴 수 있다.

라운드로빈 (Round-Robin)
FCFS 방식에 선점 방식과 Time Quantum(Time Slice) 개념을 추가한 방식이다. 프로세스마다 CPU를 연속적으로 사용할 수 있는 시간에 제한을 주는데, 이를 Time Quantum이라고 한다. Time Quantum시간만큼 CPU를 점유했다면, 해당 프로세스로부터 자원을 회수하고, Ready Quene의 가장 뒤로 보낸다. Time Quantum이 너무 길다면, 기존의 문제점인 호위상태가, 너무 짧다면 Context Switching이 자주 일어나게 된다.

 

즉, 같은 우선 순위의 프로세스들간 형평성 유지를 위해 정해진 시간 간격 만큼만 실행을 하고 우선 순위가 동일한 다른 프로세스에게 CPU의 할당을 넘기는 방식을 뜻한다.

 

타임 슬라이스 간격이 관건인데...

1) 너무 길면 인터랙티브한 시스템에서 문제가 될 수 있다. 입력에 대한 반응이 늦는 등...
2) 너무 짧으면 컨텍스트 스위칭이 너무 많이 발생해서 성능 저하 문제가 심각해 진다.

최근 OS들은 보통 15~20ms 간격으로 스케쥴링을 수행한다고 한다.
Windows7의 경우 약 15ms 단위 (정확하게 15.6001ms)로 스케쥴링한다.

따라서, 우리가 만든 쓰레드가 임의로(::Sleep 등) 쓰레드 컨텍스트 스위칭을 시키지 않았다 하더라도,
항상 수행되고 있다고 가정해서는 안 된다는 것을 반드시 기억해야 한다.

특정 쓰레드가 모든 프로세서를 점유하고 있다면 다른 쓰레드가 어떻게 수행될 수 있겠는가?

Window 운영체제의 경우 GetSystemTimeAdjustment 함수를 활용하면 정확한 타임 슬라이스 값을 확인할 수 있다.

DWORD timeAdjustment = 0;
DWORD timeIncrement = 0;
BOOL timeAdjustmentDisabled = FALSE;
 
GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement, &timeAdjustmentDisabled);

 

다단계 큐 (Multi-Level Queue)
프로세스를 그룹으로 나누고, 그룹마다 Queue를 둔다. Ready Queue가 여러개인 것이다. 또한 각각의 Queue마다 다른 스케줄링 방식을 적용할 수도 있다. 다음의 Fore 와 Back을 보자.

Foreground Queue 와 Background Queue
사용자와 직접 상호작용하고 있는 프로세스는 빠르게 처리되어야 하니까 Fore Queue에 모이고 라운드로빈 같은 방식을 채택하고, 그렇지 않은 애들은 일괄처리 하도록 해서 Back에 모이고 FCFS같은 비선점 방식중 하나를 채택한다.

또한 여러개의 Queue를 사용함으로써 어떤 Queue에 CPU를 오래 할당할지를 결정해야 한다.

고정 우선순위
Queue마다 우선순위를 둬서 우선순위가 높은 Queue에 프로세스가 남아있다면 반드시 모두 처리한 뒤에 다음으로 넘어간다. 오.. 앞에서 비슷한 놈이 있었다. 그렇다. SJF처럼 기아 상태가 발생할 수 있다. 우선순위가 낮은 Queue는 계속해서 밀릴 것이다.

타임 슬라이스
운영체제가 Time Slice를 두고 이 시간 비율에 따라서 Queue에 자원을 할당한다. 7:3의 비율이라면 Fore에 7, Back에 3

다단계 피드백 큐 (Multi-Level Feedback Queue)
우선순위가 낮은 Queue에서 오래 기다린 프로세스의 우선순위를 점점 올려서 우선순위가 높은 Queue로 올려주는 방식의 에이징 기법을 적용했다. 고정 우선순위에서 발생하는 기아 상태를 어느정도 해결 해 준다.

 

9.컨텍스트 스위칭과 iocp의 관계

iocp 모델은 윈도우즈에서 제공하는 I/O모델 중 최고의 성능을 자랑한다.

Completion Port객체는 Overlapped I/O에서 쓰레드 풀링과 Queue라는 메커니즘을 동시에 접목 시켰다.

 

쓰레드 풀(Pool)은 실제로 프로그램에서는 시작할 때 여러개의 쓰레드를 대기상태로 미리 생성해놓은 것을 쓰레드 풀이라 한다. 그리고 이 쓰레드 풀에 대기중인 쓰레드들 중에 현재 필요한 만큼 꺼내어 실행 상태로 바꾸어서 사용하고

다 사용한 스레드는 파괴하지 않고 다시 대기상태로 바꿔서 쓰레드 풀에 넣어주는 일련의 과정을 쓰레드 풀링 이라 한다.

 

이 쓰레드 풀링을 사용함으로서 컨텍스트 스위칭을 줄일 수 있다.

 

iocp가 내부적으로 수행하는 쓰레드 풀링은 간단하게 아래와 같은 매커니즘으로 작동한다.

 

 

GQCS함수에 진입한 쓰레드들은 IOCP Queue에 완료된 작업이 있을때까지 대기하다가,

작업이 완료된게 있으면 빠져나와(Release상태) 일을 처리하고 대기 함수에 진입하면(Pause)상태에 빠지고 빠져나오면

이어서 처리. 일을 다 처리하면 다시 다음 일감을 처리하기위해 대기한다.

 

여기서 WaitingThread Queue의 쓰레드 입출력 순서가 FIFO가 아니고 LIFO로 동작한다.

  •  컨텍스트 스위칭을 피하기 위함. 즉 방금 대기한 쓰레드가 일감이 들어오면 바로 일처리. CPU최대활용.

  • 컨텍스트 스위칭은 서로 다른 쓰레드간의 전환이 일어나는 것.
    여기서 대기 상태였던 쓰레드를 다시 실행상태로 바꾼것이고 서로 다른 쓰레드간의 전환은 일어나지 않았다.

  • 만약 마지막에 들어온 쓰레드가 아닌 다른 쓰레드가 실행상태로 바뀐다면 컨텍스트 스위칭이 일어난단 의미.
    그렇기에 LIFO구조를 사용하는 것.
    즉 A(실행)->A(대기)->A(실행)의 과정은 컨텍스위칭x. A(실행)->A(대기)->B(실행)의 과정은 컨텍스위칭O.
반응형

'기술 면접' 카테고리의 다른 글

소켓 버퍼  (0) 2024.09.26
메모리 단편화  (0) 2024.09.25
Send,Recv Buffer  (0) 2024.09.09
std::move, std::foward  (0) 2024.08.14
Memory 정리  (0) 2024.08.13