프로세스
같은 프로그램을 실행하는 프로세스는 여러 개 있을 수 있다.
프로그램의 종류
- Batch System: Jobs
- Time Shared System: User Programs, Tasks
Job = Process
프로세스는 실행 중인 프로그램이다.
하나의 프로세스 실행은 순차적으로 진행되며, 레디 큐(Ready Queue)에 들어가 선택될 때까지 대기한다.
프로세스의 내부 구성
- 프로그램 코드: 텍스트 영역
- CPU 레지스터: 현재 프로세스의 실행 정보 (PC: 다음 명령 주소)
- Stack: 임시 데이터를 저장하는 공간 (액티베이션 레코드 포함)
- 함수 파라미터, 반환값, 로컬 변수 포함
- Data Section: 전역 변수 및 static 변수
- Heap: 프로세스 종료 시까지 유지, 동적 메모리 할당 (malloc 등 시스템 콜 이용)
프로그램은 Passive한 상태이고, 프로세스는 Active한 상태이다. 프로그램이 메모리에 로드되면 Process로 변환된다.
프로세스 상태
프로세스 실행 중에는 Run, Wait, Ready 상태만 존재하며, New와 Terminated는 시작과 종료 상태이다.
- New: 프로세스가 생성됨
- Running: 명령어가 CPU에서 실행 중
- Waiting: I/O 등 이벤트 대기 중 (Waiting Queue)
- Ready: CPU 할당을 기다림 (Ready Queue)
- Terminated: 실행 종료
Running 상태에서 Ready 상태로 가는 전환은 Interrupt에 의해 발생한다. Running 상태여야 Interrupt를 받을 수 있다.
CPU 스케줄링 알고리즘 (예: Round Robin)
- 정해진 시간 동안만 실행 후 타이머 Interrupt 발생 → Ready로 전환
Process Control Block (PCB)
프로세스를 나타내는 자료구조로, 다음 정보를 포함한다 (사실 스레드, 즉 job하나마다 할당된다):
- 프로세스 상태
- 프로그램 카운터 (PC)
- CPU 레지스터 값
- 스케줄링 정보 (우선순위, 큐 포인터 등)
- 메모리 관리 정보
- Account Information (CPU 사용 시간 등)
- I/O 상태 정보 (사용 중인 I/O, 열린 파일 목록 등)
컨텍스트 스위칭
프로세스 간 CPU를 스위치할 때 발생. 현재 프로세스의 PCB를 저장하고, 다음 프로세스의 PCB를 복원한다.
스레드는 기본적으로 하나의 실행 흐름을 가지며, 함수 단위를 기반으로 한다. 멀티스레드 프로세스에서는 실행 흐름(프로그램 카운터)이 여러 개 존재할 수 있다.
리눅스에서 프로세스 표현
리눅스에서는 프로세스를 구조체로 표현한다:
- pid_t pid
- long state (생성, 종료, Ready, Run, Wait 등)
- 부모 포인터 (init의 경우 null)
- 자식 리스트
- 열린 파일 구조체들
- 메모리 주소, 크기 등 할당 정보
프로세스 스케줄링
레디 큐에 여러 프로세스가 있을 경우 어떤 것을 먼저 실행할지 결정해야 한다.
스케줄링 큐의 종류
- Job Queue: 시스템의 프로세스가 생성되기 전에 거쳐가는 큐로 디스크에 있지만 메모리에 없는 프로세스가 담긴다.
- Ready Queue: 실행 대기 중인 프로세스
- Device Queue: 디바이스 마다 가지고 있는 큐로, I/O 대기 중인 프로세스가 큐잉 된다.
Queueing Diagram 예시
스케줄러 종류
- Short-term Scheduler (CPU Scheduler): Ready Queue에서 CPU에 할당할 프로세스 선택
- Long-term Scheduler (Job Scheduler): Job Queue에서 Ready Queue로 보낼 프로세스를 결정
- Medium-term Scheduler: 메모리에서 프로세스를 스왑 아웃할지 결정
멀티프로그래밍의 정도는 Ready Queue에 프로세스가 얼마나 있는지(Long-term Schedule), 그리고 그 성격에 따라 달라진다:
- I/O-bound Process
- CPU-bound Process
Long-term Scheduler는 이들을 적절히 혼합하여 시스템의 효율을 높인다.
Medium-term scheduler (일부만 존재)
- 멀티프로그래밍의 정도(Degree of Multiprogramming)를 줄여야 할 때 추가될 수 있다.
- 이는 시스템에 동시에 메모리에 올라가 있는 프로세스 수를 줄이는 역할을 한다.
- 이 때 수행되는 기법이 바로 스와핑(Swapping) 이다.
스와핑(Swapping)
- 스와핑이란, 현재 메모리에 존재하는 프로세스를 디스크로 이동시켜 일시적으로 제거하는 것이다.
- 나중에 다시 그 프로세스를 실행할 때는 디스크에서 메모리로 다시 불러와 실행을 이어간다.
- 이를 통해 메모리의 부담을 줄이고, 보다 우선순위가 높은 프로세스를 실행할 수 있도록 한다.
모바일 시스템의 멀티태스킹
iOS
- 한 번에 하나의 Foreground Process만 실행
- 오버헤드가 작은 프로세스는 실행시키고, 나머지는 Suspend 상태
Android
- Foreground, Background Process 모두 실행 가능
- Background는 Service로 실행 (UI 없음, 메모리 적음)
Context Switch
다른 프로세스로 전환 시 PCB 저장/복원 작업이 필요 → 오버헤드 발생 → HW 지원 여부에 따라 효율성이 달라짐
ex) 여러 컨텍스트 정보의 집합을 제공하는 아키텍처도 존재한다.
OS Operation on Processes
운영체제는 다음 기능을 제공해야 한다:
- Process Creation
- 부모가 자식을 생성 (트리 구조)
- pid로 구분 (예: getpid)
- 자원 공유 여부 결정
- 부모와 자식이 concurrent하게 실행할지 부모가 자식이 끝날때까지 대기 여부 결정
- Process Termination
프로세스의 종료
1. 프로세스 종료의 기본 흐름
- 프로세스는 자기 자신을 종료할 수 있고, 경우에 따라 다른 프로세스를 종료시킬 수도 있다.
- 일반적으로 마지막 명령문이 실행된 후, exit() 시스템 콜을 호출한다. (main 함수가 return되면 내부적으로 exit()을 호출한다.)
- 사용자 프로그램의 메인 함수가 종료되면, 내부적으로 종료 요청이 호출된다.
- 이때 운영체제는 해당 프로세스가 사용하고 있던 모든 자원(메모리, 파일 디스크립터 등)을 deallocate한다.
2. 부모-자식 프로세스 간의 종료 관계
부모가 자식의 종료를 감지하는 경우
- 운영체제는 자식 프로세스가 종료되었을 때, 그 상태 정보를 일시적으로 보관한다.
- 부모 프로세스는 운영체제에 자식의 종료 여부를 질의하여 해당 정보를 받아올 수 있다.
- 이 과정을 통해 부모는 자식의 종료 시점이나 이유 등을 확인할 수 있고, 자원 회수를 마무리한다.
부모가 자식을 직접 종료시키는 경우
- 자식이 허용된 자원 사용량을 초과했을 때
- 자식에게 맡긴 작업이 더 이상 필요 없을 때
- 일부 운영체제에서는 부모가 종료되기 전 자식을 먼저 종료시키도록 정책이 설정되어 있다.
3. 특수한 종료 상태
Cascading Termination
- 부모가 종료되면 그에 속한 자식 프로세스들도 자동으로 종료되는 방식
- 자식뿐 아니라 자식의 자식까지 모두 제거되는 계단식 종료 구조
- 일부 운영체제에서 적용되며, 리눅스는 이 방식을 사용하지 않고 해당 자식 프로세스에게 부모(init)을 연결시켜준다.
Zombie Process
- 자식이 먼저 종료되었지만, 부모가 자식의 종료 상태를 조회하지 않은 경우 발생
- 자식의 실행은 끝났지만, 운영체제는 그 종료 정보를 부모에게 전달하기 위해 잠시 보존한다
- 이 상태의 프로세스는 시스템 자원을 일부 점유하며, 부모가 확인하면 즉시 좀비 프로세스는 제거된다
Orphan Process
- 부모 프로세스가 먼저 종료되고, 자식이 아직 실행 중인 경우 발생
- 이때 자식은 부모가 없는 상태가 되며, 대부분의 유닉스 계열 시스템에서는 init 프로세스가 새 부모 역할을 수행하게 된다
- 리눅스는 이와 같은 상황에서 자식을 init이 입양하여 정상적으로 관리한다
4. 종료 제어
- 부모와 자식은 독립적으로 concurrent하게 실행되지만, 부모가 자식의 종료 시점을 기다릴 수 있는 wait()를 운영체제가 제공한다
- 이 구조를 통해 병행 실행 중인 프로세스 간의 흐름을 제어할 수 있으며, 자식의 종료 이후에 부모가 후속 작업을 수행하는 등의 흐름 제어가 가능하다
- 자식의 종료 상태는 운영체제가 임시로 저장하며, 부모가 요청하면 이 정보를 반환하고 자원을 완전히 정리한다
멀티 프로세스 아키텍처 (크롬)
예전에 웹 브라우저는 싱글 프로세스이나, 한 사이트가 오류 생기면 모든 브라우저가 hang, crash된다.
이것을 예방하기 위해서 크롬은 멀티 프로세스 아키텍처를 가진다.
크롬은 세 가지 유형의 프로세스를 갖는다:
- Browser Process: UI, Disk, Network I/O
- Renderer Process: HTML, JS 렌더링 (Origin마다 분리)
- sandbox 기술(특정 보호받는 영역에서 실행되도록) 안에서 프로세스 실행
- 사이트 격리(Site Isolation)** 로 인해, 출처(origin)가 다르면 보통 별도의 렌더러 프로세스가 생성된다.
- Plug-in Process: 외부 임베디드 프로그램
웹 개발자가 알아야 할 크롬 렌더링 구조 요약
- 웹앱은 Renderer Process 내에서 실행됨
- 렌더링 로직은 Main Thread에서 실행됨
- JS가 Main Thread를 점유하면 UI 응답 중단
- Web Worker, OffscreenCanvas 등으로 작업 분산 가능
웹 최적화 포인트 요약
- Main Thread 병목 의심 시 Web Worker 사용
- Repaint/Reflow 최소화
- React.memo, requestAnimationFrame, lazy, Suspense 등 활용
백엔드 개발자와 브라우저 구조 연계 요약
- Browser Process가 네트워크 요청 처리
- Renderer Process는 Origin 단위로 분리 실행
- CORS, SameSite 쿠키, CSP, 캐시 전략은 렌더러 보안 및 성능과 직접 연결됨
백엔드 대응 전략
- Access-Control-Allow-Origin, SameSite=Lax 등 헤더 설정
- Content-Security-Policy, Cache-Control, gzip 등으로 보안 및 성능 최적화
Interprocess Communication (IPC)
프로세스 분류
- Independent Process
- Cooperating Process (IPC 필요)
Cooperating Process 사용하는 이유
- 정보 공유
- 계산 속도 향상
- 모듈화
- 편의성
IPC 방식 대표 두가지
- Shared Memory: User Space(메모리의 유저 프로세스 영역)에서 한 영역 공유 (동기화 문제 발생 가능)
- Message Passing: 커널 공간에 Message Queue 생성
Producer-Consumer 문제
cooperating 프로세스의 동기화 문제이다.
생산자, 소비자가 서로 통신을 하기 위해 생산자는 메세지를 큐에다가 넣고, 소비자는 큐에서 메세지를 가지고 소비를 한다.
- Unbounded Buffer: 무한 크기의 버퍼로 항상 저장 가능
- Bounded Buffer: 고정 크기의 버퍼로 공간이 없으면 동기화 문제 발생
IPC - shared memory
포인터 값을 이용해서 컨트롤한다. shared memory할당은 OS가 해주고, 그 이후에는 프로세스가 포인터를 이용해서 다룬다.
두 프로세스가 동시에 이 영역에 write등을 하려고 할때 -> 동기화 문제 책임이 전적으로 유저 프로세스에게 있다.
IPC - message passing
커널 영역에 MQ를 만들어준다. -> 공유된 영역 접근 없이 한다
- send(message)
- receive(message)
프로세스 P와 Q가 통신하려면
- 두 사이에 communication link(queue)를 구축을 해야된다.
- send/receive를 이용해서 통신한다.
구현 이슈들
- 링크를 어떻게 구축할 것인가?
- 두개의 프로세스 이상에 할당시킬건인가
- 프로세스 사이에 몇개의 링크를 할것인가
- 링크(큐)의 크기는 어떻게 설정
- 메세지의 크기는 어떻게 설정할것이냐
- unidirectional(단방향, 두 프로세스가 보내기 받기 둘다 가능) or bi-directional(역할 고정) 할것이냐
Communication 링크의 구현
- Physical
- Shared memory
- Hardware bus
- Network
- Logical (바로뒤에 자세히 설명)
- Direct or indirect
- Synchronous or Asynchronous
- Automatic or explicit buffering
Direct Communication
프로세스의 통신 대상을 지정한다 (MQ를 지정하는 것이 아니라)
send(P, message), receive(Q, mes) -> 커널에서는 중간에 MQ로 연결된다.
사용하는 입장에서는 직접하는 효과가 있다.
커뮤니케이션 링크의 특징
- 커널이 자동으로 생성해준다
- 두 프로세스 페어마다 메세지큐를 하나의 링크를 만든다
- 이 링크는 단/양방향일수 있다.
Indirect Communication
통신대상이 아닌 링크를 지정한다. (link = port = mailbox)
누가 받을지를 지정하지 않는다. send(A, message) receive(A, message)
각 큐는 유일한 id가 있다 프로세스는 공통 큐를 공유해야지만 통신을 할 수 있다.
커뮤니케이션 링크의 특징
- 링크는 프로세스가 공통 메일박스를 공유해야지 구축된다.
- 링크는 여러 프로세스에 의해 공유될수도 있다.
- 각 프로세스는 여러 메일박스를 공유할수 있다
- 이 링크는 단/양방향일수 있다.
Operations
- 새 메일 박스(port)를 생성한다. (direct에서는 이 과정 생략-OS가 알아서 만들어줌)
- 메일 박스를 통해 send, receive
- 메일 박스를 삭제
Mailbox sharing 이슈 예
- P1, P2, P3 가 공유한다
- P1이 send, P2,3이 receive
- P2, P3중 어느 프로세스가 메세지를 받을지 모호하다.
solution
- 두개의 프로세스만 링크를 공유하게 한다.
- 한번에 한프로세스만 receive 연산을 하도록 한다. (먼저 가져간 프로세스가 임자)
- 커널이 임의로 누가 가져갈지를 선택하고, sender에게 알려준다.
Synchronization
Blocking -> synchronous의 방식
- blocking send : sender는 received 될때까지 blocked된다.
- blocking receive : receiver는 메시지를 받을수 있을때까지 blocked된다.
Non-blocking -> asynchronous의 방식
- non-blocking send : sender가 메세지를 보내고 그 send()가 바로 (보낼수 없으면 리턴, 보낼수 있으면 보내고 리턴) 자신의 역할을 이어간다.
- non-blocking receive : receiver는 receive에서 바로 아래 정보를 리턴 받는다
- valid message 또는 Null message
다른 컴비네이션으로 조합 가능하다
send, receive가 blocking이면, rendezvous라고 한다.(랑데뷰)
'CS 지식 > 운영체제 (OS)' 카테고리의 다른 글
[운영체제] OS의 스케쥴링의 방식과 멀티레벨 스케쥴링, 스레드 스케쥴링 (PCS, SCS) - CPU Scheduling (0) | 2025.04.15 |
---|---|
[운영체제] OS의 스레드 종류(User, Kernel)와 관련 아키텍처 소개 (1) | 2025.04.13 |
[운영체제] OS의 구조와 서비스 종류 소개, 시스템 프로그램과 시스템 콜 소개 (0) | 2025.04.13 |
[운영체제] OS의 듀얼모드와 작업(Operations)의 종류와 관리 기능 소개 (0) | 2025.04.13 |
[운영체제] OS의 개념과 구조, 컴퓨터 시스템 아키텍처 소개 (1) | 2025.04.13 |
댓글