우리의 컴퓨터 프로그램은 모두 하드웨어(HW) 기반 환경 위에서 실행된다.
하지만 하드웨어 자원은 한적되어있고,
이를 직접 다루기에는 복잡하고 비효율적일 수 있다.
그렇다면 이 하드웨어 위에서 프로그램들이 원활하게 돌아가도록 돕는 존재는 무엇일까? 바로 운영체제(OS)이다.
운영체제란?
운영체제(Operating System, OS)는 컴퓨터 시스템의 핵심 소프트웨어(SW)로, 컴퓨터 하드웨어와 응용 프로그램 간의 상호작용을 관리하고 제어하는 역할을 한다.

운영체제의 주된 목적은 사용자와 하드에워 사이의 인터페이스를 제공하여,
응용프로그램이 보다 효율적이고 안정적으로 실행될 수 있도록 지원하는 것이다.
또한 운영체제는 시스템 자원을 효율적으로 관리해,
여러 응용 프로그램이 동시에 원활하게 동작할 수 있도록 보장한다.
이제 운영체제에서 중요한 개념들에 대하여 알아보자
운영체제의 구조
운영체제는 단일한 프로그램처럼 보이지만, 실제로는 여러 구성 요소가 유기적으로 협력하며 동작하는 복합적인 시스템 소프트웨어이다!

운영체제의 구조는 크게 다음과 같은 계층으로 나눌 수 있다.
1. 커널(Kernel)
운영체제의 핵심 부분으로, 하드웨어와 직접 상호작용하는 역할이다.
- 프로세스 관리: CPU 스케줄링, 문맥 교환, 프로세스 생성/종료 관리
- 메모리 관리: 가상 메모리, 메모리 할당/회수, 보호 기법 제공
- 파일 시스템 관리: 파일 생성, 삭제, 접근 제어, 디렉터리 구조 관리
- 입출력(I/O) 관리: 디스크, 네트워크, 장치 드라이버와의 통신
즉, 커널은 운영체제의 “심장”과도 같은 존재이다
2. 시스템 콜(System Call) 인터페이스
응용 프로그램이 운영체제의 기능을 직접 사용할 수 있도록 제공하는 인터페이스(API)이다.
예시를 보자
- 프로세스 관리: fork(), exec(), exit()
- 파일 관리: open(), read(), write(), close()
- 디바이스 제어: ioctl(), read(), write()
- 통신: socket(), connect(), send(), recv()
프로그램은 시스템 콜을 통해 파일 접근, 프로세스 생성, 네트워크 통신 등을 요청한다.
운영체제에서는 보안성과 안정성을 위해 CPU 실행 권한을 두 가지 모드로 구분해둔다.
- 사용자 모드
- 일반 응용 프로그램이 실행되는 영역
- 제한된 권한만 가지며, 직접 하드웨어 자원(CPU, 메모리, 디스크, 네트워크 등)에 접근할 수 없음
- 잘못된 동작으로부터 운영체제 전체를 보호하기 위한 목적
- 커널 모드
- 운영체제 핵심(Kernel)이 동작하는 영역
- 모든 하드웨어 자원에 직접 접근 가능
- 프로세스 관리, 메모리 관리, I/O 제어 등 특권 명령(Privileged Instruction) 실행 가능
즉, 일반 프로그램은 사용자 모드에서 동작하고, 하드웨어 자원에 접근할 때는 반드시 커널 모드의 도움을 받아야 합니다.
그럼 사용자모드와 커널모드가 서로 전환하려면 어떻게 하나?
1) 사용자 프로그램이 파일을 열기 위해 open() 호출
2) 시스템 콜 인터럽트 발생 → CPU 모드 전환 (User → Kernel)
3) 운영체제가 해당 요청 처리 (파일 핸들 생성, 접근 권한 확인 등)
4) 처리 완료 후 결과를 반환 → CPU 모드 전환 (Kernel → User)
5) 프로그램이 결과값을 사용하며 실행 계속
즉, 이들의 관계는 다음과 같다
- 사용자 모드: 제한된 권한, 응용 프로그램 실행
- 커널 모드: 전체 권한, 운영체제 핵심 기능 수행
- 시스템 콜: 사용자 모드 프로그램이 커널 모드 기능을 요청하는 창구
3. 사용자 인터페이스(User Interface, UI)
사용자와 운영체제 사이의 접점으로, 우리에게는 익숙한 개념일 수 있다.
크게 두 가지 형태가 존재한다.
- CLI (Command Line Interface): 명령어 기반 인터페이스 (예: Linux Shell, Windows PowerShell)
- GUI (Graphical User Interface): 그래픽 기반 인터페이스 (예: Windows 바탕화면, macOS Finder)
cli보다 gui 쪽이 좀더 시각적인 부분이라고 생각하면 된다
4. 라이브러리 및 유틸리티(Library & Utility)
운영체제는 응용 프로그램이 편리하게 실행될 수 있도록 다양한 라이브러리와 유틸리티 프로그램을 제공한다.
- 표준 라이브러리: 파일 입출력, 문자열 처리, 네트워크 기능 등
- 유틸리티 프로그램: 파일 탐색기, 시스템 모니터, 디스크 관리 도구 등
5. 드라이버
운영체제의 구조에서 드라이버(Driver)는 하드웨어 장치와 운영체제(특히 커널) 사이를 이어주는 중간 계층 역할이다.
하드웨어는 종류도 다양하고 제조사마다 제어 방식도 다르고, 운영체제가 모든 장치의 세부 동작을 직접 알 수는 없기 때문에,
장치 제조사가 제공하는 드라이버 프로그램을 통해 하드웨어를 제어한다.
즉, 디바이스 드라이버는 운영체제에게는 표준화된 인터페이스를 제공하고, 하드웨어에게는 구체적인 제어 명령을 전달하는 "번역기" 같은 역할을 해준다!
- 프린터 드라이버: 운영체제가 “문서 인쇄” 명령을 주면, 실제 프린터 기기에 맞는 명령어로 변환해 전달
- 그래픽 카드 드라이버(GPU Driver): 게임이나 그래픽 응용 프로그램에서 발생하는 복잡한 연산 요청을 GPU에 맞게 전달
- 네트워크 드라이버: 운영체제가 보내는 데이터 패킷을 실제 네트워크 카드가 처리할 수 있는 형식으로 변환
다음과 같은 식으로 운영체제는 동작하는 것이라고 볼 수 있다.
응용 프로그램 → 시스템 콜 → 운영체제 커널 → 드라이버 → 하드웨어
드라이버 덕분에 운영체제와 응용 프로그램은 하드웨어의 복잡한 동작 방식을 몰라도 표준화된 방식으로 장치를 사용할 수 있음
운영체제의 구조적 설계 방식
운영체제는 설계 철학에 따라 여러 가지 구조를 가질 수 있다.
- 단일 구조(Monolithic Kernel): 운영체제의 대부분 기능이 커널 내부에서 동작 (예: Linux)
- 계층 구조(Layered OS): 기능을 계층별로 나누어 설계 (예: THE OS)
- 마이크로커널(Microkernel): 최소한의 핵심 기능만 커널에 포함하고 나머지는 사용자 영역에서 수행 (예: QNX, Minix)
- 하이브리드 구조(Hybrid Kernel): 모놀리식과 마이크로커널의 장점을 혼합 (예: Windows NT, macOS)
프로세스
운영체제에서 가장 기본적이고 중요한 개념이 바로 프로세스(Process)이다.
프로세스는 컴퓨터에서 실행 중인 프로그램을 의미한다.
단순히 디스크에 저장된 정적인 프로그램 파일이 아니라, 메모리에 적재되어 CPU를 사용해 실제로 작업을 처리하는 "동적인 실행 단위"를 말한다.
운영체제로부터 CPU, 메모리(RAM), 파일, 네트워크 리소스 등 다양한 자원을 할당받아 독립적으로 실행되며, 각 프로세스는 자신만의 메모리 공간(Heap, Stack, Code, Data 영역)을 가진다.

예를 들어 보자.
크롬 브라우저를 실행하면 하나의 프로세스가 생성되고, 탭을 새로 열면 탭마다 추가적인 프로세스가 생성될 수 있다.
즉, "프로그램 단위"의 개별 실행 인스턴스가 곧 프로세스라고 할 수 있습니다.
그래서 우리가 보는 작업 관련 PID는 ProcessID이다.
프로세스의 주소 공간

위의 자신만의 메모리 공간에 대하여 가진다는 것을 알아보자.
1. 코드 영역 (Code Segment, Text Segment)
실행할 프로그램의 명령어(기계어 코드)가 저장되는 영역
읽기 전용(Read-only) 속성을 가지므로, 실행 중에는 변경되지 않음
여러 프로세스가 같은 프로그램을 실행할 경우, 코드 영역은 공유될 수 있음
2. 데이터 영역 (Data Segment)
프로그램 실행 중 전역 변수(Global), 정적 변수(Static), 상수(Constant) 등이 저장됨
프로그램 시작 시 할당되고, 종료 시 해제됨
실행 중 값이 변경될 수 있음 (예: int counter = 0;)
3. 힙 영역 (Heap Segment)
동적 메모리 할당 영역
malloc, new 같은 함수 호출로 실행 도중 필요한 만큼 메모리를 할당받음
프로그램이 필요에 따라 크기가 늘어나거나 줄어들 수 있음
사용 후 반드시 해제(free/delete)하지 않으면 메모리 누수(memory leak) 발생
4. 스택 영역 (Stack Segment)
함수 호출과 지역 변수가 저장되는 영역
함수가 호출될 때마다 스택 프레임(stack frame)이 생성되고, 함수 종료 시 제거됨
LIFO(Last-In-First-Out) 구조로 동작
함수 호출이 깊어지면 스택 오버플로우(Stack Overflow)가 발생할 수 있음!
프로세스 주소 공간의 구조
보통 메모리는 다음과 같은 형태로 구성

스택은 위에서 아래로 확장되고, 힙은 아래에서 위로 확장됨
스택과 힙이 서로 충돌하지 않도록 운영체제가 관리
프로세스 관리
운영체제는 각 프로세스의 상태와 실행 정보를 프로세스 제어 블록(PCB, Process Control Block)이라는 자료구조에 저장하여 관리한다.
PCB에는 다음과 같은 정보가 포함된다.
- 프로그램 카운터(PC): 현재 실행 중인 명령어의 위치
- CPU 레지스터 값
- 메모리 관리 정보(스택, 힙, 코드, 데이터 영역)
- 파일 및 I/O 자원 할당 정보
이러한 정보 덕분에 운영체제는 프로세스를 중단했다가 다시 이어서 실행하는 문맥 교환(Context Switching)을 수행할 수 있다.
운영체제는 각 프로세스의 상태와 정보를 프로세스 제어 블록(PCB)에서 저장하여 관리함
프로세스 실행에 필요한 자원
프로세스가 실행되기 위해서는 최소한 다음과 같은 자원이 필요하다.
- CPU – 명령어 실행을 위한 처리 능력
- 메모리(RAM) – 코드, 데이터, 스택, 힙 등을 저장하기 위한 공간
- 파일(File) – 실행 시 접근하는 데이터 및 프로그램 관련 파일
- 입출력 장치(I/O Devices) – 사용자 입력과 외부 장치와의 상호작용
- 저장 위치: 실행을 위해 RAM에 로드됨
- 상태: 실행 중(active) 상태이며, CPU와 메모리 같은 자원을 점유함
- 구성 요소: 단순한 명령어 집합뿐만 아니라 실행에 필요한 모든 상태 정보(프로그램 카운터, 레지스터 값, 스택, 힙, PCB 등)를 포함
프로세스는 프로세스를 실행하기 위한 최소 단위인 "태스크"를 실행하기 위하여 다음과 같은 자원을 필요로 한다
1. cpu 점유
2. 메모리(memory)
3. files
4. 입출력 장치(I/O devieces)
프로세스의 예시

- 현재 열어둔 웹 브라우저 창
- 실행 중인 게임 프로그램
- 백그라운드에서 동작하는 시스템 서비스
이처럼 사용자가 직접 실행하는 애플리케이션부터 시스템 내부의 관리 작업까지 모두 프로세스 형태로 운영체제에 의해 관리됩니다.
그러면 우리가 자주 들어본 프로그램이란 무엇일까??
프로그램
프로그램은 특정 작업을 수행하기 위해 컴퓨터 언어로 작성된 명령어들의 정적인 집합이다.
즉, "아직 실행되지 않은" 상태에서 단순히 저장되어 있는 코드 덩어리를 의미한다.
- 저장 위치 : 일반적으로 하드디스크같은 보조 기억장치에 파일 형태로 저장됨
- 상태: 실행되기 전에는 메모리에 적재되지 않은 수동적(passive) 상태로, 운영체제가 이를 로드(load)하고 실행(run)해야 비로소 "프로세스"가 된다.
- 구성 요소 : 명령어(코드)와 데이터 섹션 등으로 구성되어있음. 그 외에도 실행 시 스택이나 힙 등 공간 별도로 할당되어 동적 실행 환경 구성함
- 예시 : 워드 프로세서, 게임 실행 파일, 운영체제 유틸리티 등. 확장자로는 Windows의 .exe, macOS의 .app 파일 등이 대표적
스레드
그러면 스레드란,
스레드는 프로세스 내에서 실행되는 "가장 작은 실행 단위"이다.
하나의 프로세스 안에는 여러 개의 스레드가 존재할 수 있으며, 이들은 같은 메모리 공간을 공유한다! (멀티스레드)
스레드의 특징
스레드는 프로세스가 가진 코드, 데이터, 힙 영역을 당연히 이것도 공유한다

각 스레드는 독립적인 스택의 영역을 가진다.
프로세스 자원 공유 덕분에 스레드 간의 전환 비용이 낮다
스레드의 장점

멀티 스레드 프로그래밍을 사용하면 여러 작업을 병렬로 실행할 수 있어서 성능을 향상 시킬 수 있다!
예: 웹 브라우저의 멀티 스레드 처리( UI 렌더링 / 파일 다운로드 / 사용자 입력 처리)
→ 각각 별도의 스레드에서 동시에 실행되어 빠른 응답성을 제공한다.
스레드의 단점

같은 메모리를 공유하기 때문에 효율적일 수는 있지만, 동기화 문제(레이스 컨디션, 데드락 등)이 발생할 수 있다!
하나의 스레드가 문제를 일으키면 전체 프로세스에 영향을 줠 수 있다는 것이 가장 큰 단점이다.
프로세스 vs 스레드
위의 내용들을 다시 한 번 정리해보자.
- 프로세스(Process) : 독립적으로 실행되는 프로그램 단위
각 프로세스는 독립적인 메모리 공간(코드, 데이터, 힙, 스택)을 가짐
안정성이 높지만, 프로세스 간 통신(IPC, Inter-Process Communication) 비용이 크다
- 스레드(Thread) : 프로세스 내에서 실행되는 "작은 실행 단위"
같은 프로세스의 메모리를 공유 → 효율적
하지만 오류 전파 위험이 있어 안정성은 상대적으로 낮음
멀티 프로세스는 독립적인 실행 환경을 제공하지만 프로세스 간 통신 비용이 크다.
멀티 프로세스 vs 멀티 스레드

- 멀티 프로세스 : 각 프로세스가 완전히 독립적인 실행 환경을 제공
안정성이 높음 (한 프로세스가 죽어도 다른 프로세스에 영향 없음)
단점: 프로세스 간 통신 비용(IPC 비용)이 크고, 메모리 사용량이 많음

- 멀티 스레드 : 프로세스 자원을 공유하여 메모리 사용량이 적고 전환 속도가 빠름
빠른 응답성과 동시성 처리가 필요한 애플리케이션에 적합!
단점: 스레드 하나의 문제 → 전체 프로세스 영향
그래서
프로세스는 독립성과 안정성, 그리고 스레드는 효율성과 속도를 강조한다!
cpu 집약적인 작업(ex. 이미지 처리, 연산 등)은 멀티프로세스가 확실히 유리하다.
하지만 빠른 응답성과 동시성 처리(ex. Web Server, 게임 엔진, 채팅 등)은 멀티스레드가 적합하다
실제 시스템에서는 상황에 따라 멀티 프로세스 + 멀티 스레드 혼합 구조를 채택한다.
이제 프로그램을 다루다보면 자주 마주칠 수 있는 것 중 하나인 인터럽트에 대하여 알아보자.
인터럽트란 무엇일까?
인터럽트
인터럽트의 의미 자체는 "CPU의 작업을 방해하는 신호"이다.
왜 CPU의 작업을 방해해야는지에 대하여 알아보자.
만약 인터럽트가 존재하지 않는 환경이라면,

CPU는 입출력 장치가 작업을 끝낼 때까지 무한 대기(busy waiting)를 해야 한다. 이는 CPU 자원을 낭비하는 비효율적인 방식이다.
하지만 하드웨어 인터럽트가 존재한다면??

위의 그림처럼 CPU는 다른 작업을 수행하다가도 입출력 장치가 완료 신호를 보냈을 때만 대응하면 된다.
즉, 대기 대신 다른 작업을 수행할 수 있는 구조로 변화할 수 있다.
인터럽트는 주로 크게
동기 인터럽트 / 비동기 인터럽트
두 가지로 구분 될 수 있다.

동기 인터럽트 (Synchronous Interrupt)
CPU가 명령어를 실행하는 과정에서 발생
예: 잘못된 메모리 접근(페이지 폴트), 0으로 나누기 예외(Divide by Zero)
비동기 인터럽트 (Asynchronous Interrupt)
CPU와 독립적으로 외부 장치가 발생시키는 이벤트
예: 키보드 입력, 디스크 입출력 완료 신호, 네트워크 패킷 도착
인터럽트 요청의 주체
인터럽트를 발생시킬 수 있는 주체는 굉장히 다양하다.
대표적으로 입출력 장치(I/O Device)들이 있으며, 키보드, 마우스, 디스크, 네트워크 카드 등 거의 모든 장치가 인터럽트 요청을 보낼 수 있다.

각 인터럽트 요청은 고유한 메모리 주소(인터럽트 벡터)에 연결되어 있으며, CPU는 이를 참조하여 해당 장치에 맞는 인터럽트 서비스 루틴(ISR, Interrupt Service Routine)을 실행한다.
이 중에서 하드웨어 인터럽트에 대하여 더 깊게 알아보자.
하드웨어 인터럽트의 처리 순서
1) 인터럽트 요청: 입출력 장치가 CPU에 인터럽트 신호를 보냄
2) 인터럽트 감지: CPU는 실행 사이클이 끝나고 명령어를 인출하기 전, 항상 인터럽트 발생 여부를 확인
3) 인터럽트 가능 여부 확인: CPU는 인터럽트 플래그를 체크하여 현재 인터럽트를 받아들일 수 있는지 판단
4) 현재 작업 백업: 인터럽트를 받아들일 수 있다면, CPU는 현재 레지스터 값과 프로그램 카운터(PC)를 백업
5) 인터럽트 서비스 루틴 실행: CPU는 인터럽트 벡터를 참조하여 해당 장치의 ISR을 실행
6) 원래 작업 복구: ISR이 끝나면 백업된 레지스터와 PC 값을 복원하여 이전 작업을 재개

즉, 인터럽트가 발생하면 위의 그림처럼
CPU의 일반적인 명령어 사이클(fetch-decode-execute)에 추가적인 인터럽트 사이클이 삽입된다.
이 덕분에 CPU는 실행 중이던 프로그램을 잠시 멈추고(interrupt),
인터럽트 처리를 수행한 뒤,
다시 원래 프로그램으로 돌아올 수 있다.
인터럽트의 필요성
현대의 운영체제는 여러 프로그램과 입출력 장치를 동시에 다루어야 한다.
인터럽트는 실행 중이던 프로그램을 잠시 중단시키고, 긴급하게 처리해야 할 요청(예: 네트워크 패킷 도착)을 먼저 처리하게 한다.
이 메커니즘 덕분에 멀티태스킹(Multitasking)과 멀티프로세싱(Multiprocessing)이 안정적으로 구현된다.
여태까지의 내용이 하드웨어 비동기 인터럽트의 요청이었다면,
이제는 동기 인터럽트에 대하여 알아보자.
동기 인터럽트는 반면에 "예외"라고 불리기도한다.
예외(Exception)
내부 요인에 의하여 발생하는것으로,
CPU가 명령어를 실행하는 도중 옿류나 특수 상황을 만나면 발생한다!
예: 0으로 나누기(Divide by Zero), 잘못된 메모리 접근(Page Fault), 산술 오버플로우
동기적인 인터럽트라고 불리면서,
cpu가 특정 명령어를 실행하는 과정에서 "즉시"발생한다. (그래서 동기 인터럽트라고 불림)
정리
| 구분 | 인터럽트(Interrupt) | 예외(Exception) |
| 발생 원인 | 외부 장치(I/O, 타이머 등) | CPU 내부 실행 중 오류 |
| 발생 시점 | 비동기 (언제든 발생 가능) | 동기 (명령어 실행 중) |
| 목적 | 외부 이벤트 처리 | 오류 처리 및 복구 |
| 예시 | 키보드 입력, 디스크 완료 | 0으로 나누기, 페이지 폴트 |
| 처리 루틴 | ISR (Interrupt Service Routine) | Exception Handler |
REF
- 혼자 공부하는 컴퓨터 구조+운영체제(저자: 강민철)
'CS > 운영체제' 카테고리의 다른 글
| [CS/운영체제] 뮤텍스와 세마포어 (0) | 2025.10.28 |
|---|---|
| [CS/운영체제] CPU 스케줄링 알고리즘 (2) | 2025.10.22 |
| [CS/운영체제] 프로세스 관리와 통신 (1) | 2025.10.14 |