CS + 인프라/운영체제

[운영체제] : 쓰레드는 많으면 좋나요? - 1탄 : 프로세스 탐구

공대키메라 2025. 5. 12. 21:15

필자는 다음과 같은 질문을 받았다.
 

면접관 : 쓰레드가 뭐죠? 쓰레드를 많이 써서 사용하면 항상 빠를거 같은데 ... 정말 그런가요?

나 : (아닌거 아는데 설명을 못함) ㅠㅠ...

 
늘 공부를 할 때는 대충이 아닌 꼼꼼함이 강려크한 엔지니어의 소양이라고 생각한다.
 
이 근원적으로 가장 먼저 세트로 같이 비교되는 프로세스가 뭔지를 먼저 알아볼 것이다.

그 다음에 쓰레드가 도대체 뭔지, 밑바닥부터 다시 다 관련 서적과 내용을 내 눈으로 담고 정리할 예정이다.
 
그러면... 해당 질문에 대한 답변을 위한 여정을 시작해 보겠다.
 
해당 내용은
 
운영체제 10판 (원서명 : Operating System Concepts, 10th Edition, International Edition)
퍼스트북 / Abraham Silberschatz, Peter Baer Galvin, Greg Gagne 
 
을 뼈대로 필자가 코드는 제외하고 개념을 이해하기 위해 여러 인터넷의 내용을 참고했다.`
 

들어가기에 앞서

초창기 컴퓨터는 작업을 실행하는 일괄처리 시스템이었다.
 

일괄 처리 시스템이란 다수 개의 프로그램을 읽어 저장해놓되, 한번에 한개씩 프로그램을 실행시켜주는 방식을 말한다.

특징은 실행할 작업들을 모아서 한 번에 실행하는 것이다. 순차적으로 말이다. 이러면 실행 중에 개입이 불가능하다.

 
그 다음으로는 시분할 시스템이 뒤를 이었다.
 

시분할 시스템은 여러 사용자가 동시에 컴퓨터를 사용할 수 있도록 CPU 시간을 나눠서 사용하는 시스템이다.

모든 사람이 컴퓨터를 사용한다면 각자 다른 게임을 할 것이다. 그러면 모든 사람이 컴퓨터를 나누어서 사용해서 동시에 반응을 얻게 된다.

여기서 라운드 로빈(Round Robin), 문맥 교환(Context Switching), 시간단위(Time Quantum) 같은 개념이 등장한다.

* 라운드 로빈?
선점형 스케줄링의 하나로 프로세스들 사이에 우선순위를 두지 않고, 순서대로 시간단위로 CPU를 할당하는 방식.
만약 10ms 로 시간단위를 설정하고 A, B, C 프로세스가 있다면 A, B, C는 순서대로 우선순위에 상관없이 10ms씩 작업을 실행한다.

* 문맥 교환?
하나의 프로세스가 CPU를 사용 중인 상태에서 다른 프로세스가 CPU를 사용하도록 하기 위해, 이전의 프로세스의 상태(문맥)를 보관하고 새로운 프로세스의 상태를 적재하는 작업

 
그 다음으로는 다중 프로그래밍이 뒤를 이었다.


다중 프로그래밍 (Multi-programming)이란 CPU 작업과 입출력 작업을 병행하는 것이다.

CPU 이용과 처리량을 향상시킬 수 있다.

목적은 CPU의 이용을 최대화하기 위하여 항상 어떤 프로세스가 실행되도록 하는데 있다.

 

1. 프로세스?

프로세스란 실행 중인 프로그램이다.
 
프로세스의 현재 활동의 상태는 프로그램 카운터 값과 프로세서 레지스터의 내용으로 나타난다. 
 
프로세스는 다음과 같은 구조로 되어 있다.
 

  • 텍스트 섹션 - 실행 코드
  • 데이터 섹션 - 전역 변수
  • 힙 섹션 - 프로그램 실행 중에 동적으로 할당되는 메모리
  • 스택 섹션 - 함수를 호출할 때 임시 데이터 저장장소(예: 함수 매개변수, 복귀 주소 및 지역 변수)

 
텍스트, 데이터 섹션의 크기는 고정. 프로그램 실행 동안 크기가 변하지 않는다.
 
스택, 힙 섹션은 실행 중에 동적으로 줄어들거나 커질 수 있다.
 
함수가 호출될 때 마다 함수 매개변수, 지역변수 및 복귀 주소를 포함하는 활성화 레코드가 스택에 푸쉬되고, 함수에서 제어가 되돌아오면 스택에서 활성화 레코드가 팝된다.
 
 

https://www.geeksforgeeks.org/process-in-operating-system/

 

2. 프로세스의 상태

 

출처 : https://tecadmin.net/linux-process-status/

 
프로세스는 실행되며 상태가 변한다.
 

  • Created : 프로세스 생성
  • Running : 명령어 실행
  • Waiting : 프로세스가 이번트가 일어나길 대기중
  • Ready : 프로세스가 처리기에 할당되기를 기다림.
  • Terminated : 프로세스 실행 종료.

 

3. 프로세스 제어 블록

프로세스 제어 블록(Process Control Block, 줄여서 PCB)은 특정한 프로세스를 관리할 필요가 있는 정보를 포함하는 운영 체제 커널의 자료 구조이다. 
 
약간의 회계 데이터와 함께 프로세스를 시작시키거나 다시 시작시키는데 필요한 모든 데이터를 위한 저장소 역할을 한다.
 
PCB는 일반 사용자가 접근하지 못하도록 보호된 메모리 영역 안에 남는다. 일부 운영 체제에서 PCB는 커널 스택의 처음에 위치한다. 프로세스가 자기 PID를 임의로 변경하면 안되기 때문이다.
 

 

포인터(Pointer)

  • 역할: 프로세스 상태가 전환될 때 현재 위치를 유지하기 위해 저장되는 스택 포인터
  • 용도: Context Switching 시 스택의 현재 위치를 기억

프로세스 상태(Process State)

  • 역할: 프로세스의 현재 상태를 저장
  • 상태 종류: 생성, 준비, 실행, 대기, 종료

프로세스 번호(Process Number)

  • 역할: 각 프로세스에 할당된 고유 식별자
  • 명칭: PID(Process ID)라고도 함
  • 용도: 시스템에서 프로세스를 구분하기 위해 사용

프로그램 카운터(Program Counter)

  • 역할: 프로세스가 다음에 실행할 명령어의 주소를 저장
  • 용도: 프로세스가 재개될 때 정확한 위치에서 실행을 계속하기 위함

레지스터(Register)

  • 역할: 프로세스가 사용하던 CPU 레지스터 값들을 저장하는 데이터 구조
  • 동작 과정:
    • 프로세스 실행 중 시간할당량 종료 시 → 레지스터 값을 PCB에 저장
    • 프로세스가 다시 실행될 때 → PCB에서 레지스터 값을 읽어서 CPU 레지스터에 복원
  • 목적: Context Switching의 핵심 요소

PCB는 커널에 저장된다고 하는데, CPU의 레지스터가 아니니 주의!
PCB의 레지스터 필드에는 CPU가 현재 실행 중인 프로세스의 작업 상태 전체를 저장한다.

메모리 제한(Memory Limits)

  • 역할: 운영체제가 사용하는 메모리 관리 시스템 정보
  • 포함 내용: 페이지 테이블, 세그먼트 테이블 등
  • 용도: 프로세스의 메모리 영역 관리

열린 파일 목록(List of Open Files)

  • 역할: 프로세스가 현재 열어놓은 파일들의 목록
  • 용도: 파일 입출력 작업 추적 및 관리

 

4. PCB의 생성 과정

그래... PCB가 그래 이런 구조구나. 그러면 어떻게 생기는건가?
 

1. 프로세스의 생성 요청

사용자가 프로그램을 실행하거나 실행 중인 프로세스가 fork() 시스템 콜을 호출할 때 발생
 

2. 메모리 할당

운영체제는 새 프로세스를 위한 주소 공간을 할당
 

3. PCB 생성

운영체제는 커널 영역에 PCB를 생성하고 초기화한다. OS 가 프로세스를 만들면 커널에 PCB로 함께 생성된다.
프로세스는 생성이 되면 사용자 메모리 영역에 올라가 있다. 일반 애플리케이션 프로세스들이 사용하는 영역이다.
 

4. PCB 초기화

프로세스 ID, 상태, 플포그램 카운터, 레지스터 값, 메모리 관리 정보 등을 초기화한다.
 
그 후에 이제는 이 잘 생성된 프로세스를 어떻게 동작시킬지 선택해야 한다.
 
다음 프로세스 스케줄링에서 보자.


5. 프로세스 스케줄링

기존의 시분할 프로그래밍은 강제적으로 시간 할당량에 따라서 실행 후 프로세스를 전환했지만,
 
다중 프로그램밍에서는 I/O나 자원 대기 시 프로세스를 전환한다. 
 
즉, 프로세스가 자발적으로 CPU의 점유를 포기할 때 변경이 되는것이다. CPU 를 최대한 효율적으로 사용하는 것을 목표로 한다.
 
 
다중 프로그래밍에서 프로세스의 일반적인 동작을 고려해야만 잘 사용할 수 있다.
 

출처 : https://tecadmin.net/linux-process-status/

프로세스의 스케줄링의 흐름

해당 스케줄링을 이해하기 위해 열심히 책을 읽었는데, 내용이 좀 불친절했다.
 
필자는 클로드 AI에게 이를 이야기 형식으로 만들어달라고 했다.
 
이에 대해 읽으면 좀 더 이해가 잘되니 다음을 보면 좋다. 정말 잘 정리해서 너무 좋다...(개발자의 미래는 과연... ㅠㅠ)
 

더보기

프로세스 A와 B의 하루

Chapter 1: 새로운 시작

오전 9시 - 사용자가 Word 프로그램(Process A)을 더블클릭

  • Process A가 Created 상태로 생성
  • "아! 새로운 프로세스가 태어났다!"

오전 9시 1초 - 메모리 관리자가 A를 확인

  • 메모리에 충분한 공간이 있음
  • Admitted: Process A가 Ready Queue로 이동
  • "좋아, 너는 실행할 자격이 있어!"

오전 9시 2초 - 스케줄러가 Ready Queue를 확인

  • Ready Queue에 A만 있음
  • Dispatched: Process A가 Running 상태로
  • "자, 이제 CPU를 마음껏 써!"

Chapter 2: B의 등장

오전 9시 5초 - A가 열심히 실행 중

  • 사용자가 Chrome(Process B) 실행
  • Process B가 Created 상태로 등장
  • "새로운 경쟁자가 나타났다!"

오전 9시 6초 - B도 메모리 할당 성공

  • Admitted: Process B가 Ready Queue
  • Ready Queue: [B]
  • "잠깐만, 내 차례는 언제야?"

오전 9시 7초 - Time Quantum(50ms) 종료!

  • Interrupt: Process A가 Ready 상태로
  • Dispatched: Process B가 Running 상태로
  • Ready Queue: [A]
  • "교대할 시간이야!"

Chapter 3: I/O의 함정

오전 9시 8초 - B가 파일 다운로드 시작

  • I/O Request: Process B가 Waiting 상태로
  • Device Queue (Network): [B]
  • Dispatched: Process A가 다시 Running
  • "좋아, 다시 내 차례!"

오전 9시 10초 - A가 문서 저장 시도

  • I/O Request: Process A도 Waiting 상태로
  • Device Queue (Disk): [A]
  • 어라? CPU가 비었다!
  • "모두 I/O로 빠지면 CPU는 뭘 하지?"

Chapter 4: 새로운 프로세스들

오전 9시 11초 - 사용자가 Spotify(Process C) 실행

  • Process C: CreatedAdmittedReady
  • Dispatched: Process C가 Running
  • "기회는 준비된 자에게!"

오전 9시 12초 - A의 디스크 I/O 완료

  • I/O Complete: Process A가 Ready
  • Ready Queue: [A, C]
  • "다시 돌아왔다!"

오전 9시 13초 - B의 네트워크 I/O 완료

  • I/O Complete: Process B가 Ready
  • Ready Queue: [A, B]
  • C는 Running
  • "드디어 다 모였네!"

Chapter 5: 혼란의 시간

오전 9시 15초 - Time Quantum 끝남

  • Interrupt: C가 Ready
  • Dispatched: A가 Running
  • Ready Queue: [B, C]

오전 9시 16초 - 사용자가 Word 종료

  • Exit: Process A가 Terminated
  • Dispatched: B가 Running
  • "안녕, A야. 수고했어!"

오전 9시 18초 - B도 브라우저 종료

  • Exit: Process B가 Terminated
  • Dispatched: C가 Running
  • "이제 Spotify만 남았다!"

Chapter 6: 엔딩

오전 9시 20차 - 사용자가 음악 종료

  • Exit: Process C가 Terminated
  • 모든 프로세스가 종료됨
  • CPU가 다시 한가해짐
  • "오늘도 무사히 끝!"

 

6. 프로세스 간 통신

물론 프로세스는 독립적일 수 도 있지만 협력적일 수 도 있다.
 
프로세스가 실행 중이 다른 프로세스들에 영향을 주거나 받는다면 이는 협력적 프로세스들이다. 
 
이는 정보공유, 계산 가속화, 모듈성을 위해서 제공한다.
 
협력적 프로세스들은 데이터를 교환할 수 있는, 즉 서로 데이터를 보내거나 받을 수 있는 프로세스 간 통신 기법(Interprocess Communication, IPC)이 필요하다.
 
프로세스간 통신에는 공유메모리메시지 전달 두 가지 모델이 있다.
 

6.1 공유메모리 시스템에서의 프로세스간 통신

 
 
공유메모리를 사용하는 IPC는 공유 메모리 영역을 구축해야 프로세스들이 통신이 가능하다.
 
일반적으로 운영체제는 한 프로세스가 다른 프로세스의 메모리에 접근하는 것을 금지하지만,
 
공유 메모리는 둘 이상의 프로세스가 이 조건을 제거하고 공유 영역에 읽고 써서 정보를 교환할 수 있다.
 
책에서는 생성자-소비자 문제로 이를 설명하고 있다.
 

6.2 메시지 전달 시스템에서의 프로세스 간 통신

메시지를 통해서 프로세스 간 통신을 지원하다.
 
이 방식은 동일한 주소 공간을 공유하지 않고도 프로세스들이 통신을 하고, 그들의 동작을 동기화할 수 있도록 허용하는 기법을 제공한다. 이는 특히 분산 환경에서 유용하다.
 
메시지 전달 시스템은 최소한 두 가지 연산을 제공한다. (send, receive)
 
프로세스 P와 Q가 통신을 원하면, 반드시 서로 메시지를 주고 받아야 한다. 
 
이를 구현하는 방법은 다음과 같다.
 
1. 직접 또는 간접 통신
2. 동기식 또는 비동기식 통신
3. 자동 또는 명시적 버퍼링
 

직접 통신

통신을 원하는 각 프로세스는 통신의 수신자 또는 송신자의 이름을 명시한다.
 

간접 통신

메시지들을 메일박스 또는 포트로 송신하고 그것으로부터 수신한다.
 

6.3 동기화

메시지 전달은 봉쇄형(blocking)과 비봉쇄형(non-blocking) 방식으로 전달된다. 이 두 방식은 각각 동기식, 비동기식이라고도 알려져 있다. 받고 보내는거에 따라서 흐름을 확인해보자.
 

  • 봉쇄형 보내기 : 데이터를 보낼 때, 데이터가 완전히 전송될 때까지 프로그램의 흐름이 멈춤
  • 비봉쇄형 보내기 : 데이터 전송을 시작한 후, 전송 완료 여부와 상관없이 프로그램이 다음 작업을 계속 수행
  • 봉쇄형 받기 : 데이터가 도착할 때까지 프로그램의 실행이 멈추고 대기
  • 비봉쇄형 받기 : 데이터가 도착했는지 확인만 하고, 없으면 즉시 제어를 반환

 

7. 파이프

파이프는 두 프로세스가 통신할 수 있게 하는 전달 메커니즘 중 하나이다.
다시말하면, IPC를 위한 메커니즘중 하나이다.
 

7.1 일판 파이프(혹은 익명 파이프 - anonymous pipe)

이름이 없는 임시 파이프로, 파일 시스템에 항목이 생성되지 않는다.
오직 부모-자식 관계의 프로세스 간에만 사용이 가능하며 또
프로세스가 끝나면 자동으로 소멸되고 단방향 통신(읽기 혹은 쓰기)만 가능하다.
 

7.2 지명 파이프(Named pipe)

지명 파이프는 좀 더 강력한 통신 도구를 제공한다. 통신은 양방향으로 가능하며 관련없는 프로세스들 간에도 통신이 가능하다.
 
명시적으로 삭제할 때 까지 파일 시스템에 존재하면 당방향 통신이다. 
 
 
이 "이름(Named)"이 붙어있다는 것은 프로그래밍적으로 중요한 의미를 갖는다.
 
서로 관련 없는 프로세스들도 동일한 이름을 통해 같은 파이프에 접근할 수 있으며(전역적 식별자)
 
파일 시스템에 등록되어 프로세스 생명주기와 독립적으로 접근한다(지속성)
 
또, 이름을 알고 있는 모든 프로세스가 접근할 수 있다(접근성).
 


 
여태 우리가 이야기한 프로세스 모델은 한 프로세스가 하나의 제어 스테드로 프로그램일 실행한다 가정하였다.
 
1. 해당 내용에서 우리는 프로세스란 무엇인지,
 
2. 프로세스는 어떤 상태를 가지는지,
 
3. 이를 제어하기 위한 프로세스 제어 블록의 구조를 알아보았고,
 
4. 프로세스 스케줄링 방식에서는 정확히 어떤 흐름을 통해 프로세스의 상태가 변하고 작동하는지 보았다.
 
5. 마지막으로 프로세스간에 통신을 위해서는 무엇이 있는지도 보았다.
 


 
다음에 이어서는 운영체제에서의 쓰레드에 대해서 알아보려고 한다.
 
다음을 읽으면 원하는 대답을 자세히 할 수 있을까? 과연? 두구두구!~
 
출처:
라운드_로빈_스케줄링(위키피디아)
문맥_교환(위키피디아)
프로세스_제어_블록(위키피디아)
프로세스 컨트롤 블록
다중 프로그래밍(위키피디아)
운영체제 10판 (원서명 : Operating System Concepts, 10th Edition, International Edition)
퍼스트북 / Abraham Silberschatz, Peter Baer Galvin, Greg Gagne  3장 프로세스