dh_0e

[특강] 프로세스, 스레드, 컨텍스트 스위치 본문

내일배움캠프/특강

[특강] 프로세스, 스레드, 컨텍스트 스위치

dh_0e 2024. 7. 12. 11:51

프로세스

  • 프로그램이 실행이 되어 메모리에 올라온 순간부터 프로세스라 불림
  • 작업 관리자에서 프로세스 목록을 볼 수 있음
  • 프로그램이 프로세스로 진화하는 순간 자체적인 메모리 공간과 시스템 자원을 할당받음
  • 기본적으로 1) 코드 2) 데이터로 이루어져 있는 프로그램이 프로세스로 올라가면 다음 사진과 같이 구성됨

 

출처: https://icarus.cs.weber.edu/~dab/cs1410/textbook/4.Pointers/memory.html

 

스택

  • 일반적으로 함수 스코프에 해당되는 데이터들을 담는 곳
  • 지역변수, 파라미터들을 담고 있음
  • 함수 스코프에 해당되는 내용이다 보니 함수에서 함수를 부르는 재귀 호출의 경우에는 종료 조건을 제대로 설정해놓지 않으면 stack overflow가 발생을 할 수 있음

  • 동적인 메모리를 할당하는 곳
  • Javascript에서는 기본적으로 참조 타입(e.g. 객체)을 힙에 저장을 하고 있음
  • Java에선 new 키워드를 사용하면 힙에 저장됨

데이터

  • 일반적으로 전역 스코프에 해당되는 데이터들을 담는 곳
  • 전역 변수, static 변수들을 담고 있음

텍스트

  • 실행코드 및 함수를 담고 있음
  • CPU가 이 텍스트 영역에 저장된 명령을 하나씩 가져가서 처리하는 구조
    • CPU 머신 사이클이 발생

 

 

스레드 (Thread)

출처: https://www.cs.uic.edu/~jbell/CourseNotes/OperatingSystems/4_Threads.html

 

  • 프로세스의 일꾼으로 프로그램의 명령어를 실행하는 가장 작은 단위
  • 프로그램의 진입점부터 시작해서 한 줄씩 실행해나감
  • Node.js는 싱글 스레드이며 다른 언어로 작성된 프로그램은 멀티 스레드 기반으로 작성할 수 있음
  • 멀티 스레드로 구동이 되는 프로그램에선 각각의 스레드는 부모 프로세스 메모리를 공유함
  • 스레드는 각자의 콜 스택을 갖고 있으며, 힙과 데이터 섹션은 공유

 

 

스레드의 생명 주기

상태 천이 다이어그램

New

  • 스레드 객체가 생성되었지만 아직 시작되지 않은 상태
  • 다만, 스레드 객체를 개별적으로 생성하는 경우는 별로 없어 크게 신경 쓰지 않아도 되는 상태임

Runnable

  • 스레드가 실행될 준비가 된 상태
  • 스레드 풀을 생성한 뒤, 스레드들은 바로 사용 가능하고 각 스레드들의 상태가 Runnable이 됨
  • 아래에 나오는 Waiting 상태들은 특수한 상황에서의 대기고 Runnable이 실질적인 대기 상태임

Running

  • 스레드가 현재 CPU에서 실행 중인 상태
  • 운영체제의 스케줄러는 자동으로 스레드 풀에 있는 스레드 중 하나를 선택
  • 선택이 된 스레드는 정말 짧은 시간만 실행하게 되고 시간이 종료되면 다시 Runnable 상태로 돌아감

 

💡 Runnable ↔ Running의 순환이 기본인데 이러한 플로우는 시분할 시스템의 기본. 저렇게 2개의 상태 기준으로 상태가 수시로 순환되는 것을 Context Switch라고 부름

 

Blocked

  • 스레드가 lock 획득을 기다리는 상태
    • lock: 다른 스레드가 해당 변수에 접근하지 못하도록 제한하는 것
  • 혹은, I/O 작업을 진행 중에도 해당 상태로 변할 수 있음
  • 획득 이후에는 Runnable 상태로 돌아감

 

Waiting

  • 다른 스레드의 특정 작업 완료를 무기한 기다리는 상태
  • Thread.join()과 같은 메서드를 호출하면 발생
    • join: 특정 스레드의 작업 완료를 기다리도록 지시하는 메서드
    • JavaScript의 Promise.all과 비슷함
      • 차이점: join을 부르면 블로킹이 되나 Promise.all은 그렇지 않음

 

Timed Waiting

  • Thread.sleep() 호출 시 전환되는 상태
  • Thread.sleep()이 끝나면 다시 Runnable 상태로 전환

 

Terminated

  • 스레드의 실행이 완료되어 종료된 상태
  • 고정된 스레드 풀의 풀 사이즈를 맞춰줘야 하므로스레드 풀에서 새로운 스레드를 하나 더 생성

 

컨텍스트 스위치

  • 스레드의 상태가 Runnable ↔ Running으로 지속적으로 변하는 과정
  • 엄청나게 짧은 주기로 이뤄짐

출처: https://www.crocus.co.kr/1364

 

  1. Running → Runnable로 바뀌어야 하는 스레드의 상태를 TCB(Thread Control Block)에 저장
    • 위의 그림이 PCB인 이유는 프로세스 단위로 얘기를 하고 있기 때문
  2. OS 스케줄러가  Runnbale인 상태의 스레들 중 하나를 선택
  3. 간택당한 스레드의 상태를 TCB에서 복원
  4. 해당 스레드가 실행하던 지점으로 강제 이동
  • 연산량이 많아 컨텍스트 스위치가 잦아질 수록 스레드의 실제 실행 시간(타임 슬라이스)이 줄어들어 비효율적임
  • 컨텍스트 스위치의 주기를 너무 길게 가져가도 실행 시간이 너무 길어지게 되면 문제가 발생
  • 타임 슬라이스가 너무 길어서도 안되고 너무 짧아서도 안 되는 중도의 길을 걸어야 함

 

데몬 스레드

  • 스레드의 특수한 형태로 일반 스레드와 달리 백그라운드에서 실행
  • 모든 사용자 스레드가 종료되면 자동으로 종료되는 특수한 스레드
  • 주로 백그라운드에서 주기적으로 실행되어야 하는 작업이나 서비스에 사용되며 중요하지 않은 작업에 사용됨
  • 중요한 데이터를 처리하거나 리소스를 정리하는 작업은 일반 스레드에서 수행되어야 함
  • 예로 JVMGarvage Collector가 있음