운영체제 | Operating System
내가 볼려고 작성한 CS 공부.
⚙️ 운영체제 – 프로세스와 스레드
운영체제는 여러 프로그램이 동시에 동작할 수 있도록 자원을 관리하고,
각 프로그램이 CPU와 메모리 등의 자원을 효율적으로 사용할 수 있게 도와주는 소프트웨어다.
그 핵심 개념 중 가장 중요한 것이 바로 프로세스(Process) 와 스레드(Thread) 다.
✅ 1. 프로세스 (Process)
1.1 정의
프로세스는 실행 중인 프로그램을 의미하며, 운영체제에 의해 독립된 자원을 할당받는 단위이다.
1.2 특징
- 하나의 프로그램은 하나 이상의 프로세스로 실행될 수 있다.
- 각 프로세스는 자신만의 메모리 공간(코드, 데이터, 힙, 스택)을 가진다.
- 운영체제는 여러 프로세스를 CPU 시간 단위로 번갈아가며 실행한다.
1.3 메모리 구조
| 영역 | 설명 |
|---|---|
| 코드 영역 | 실행할 명령어가 저장됨 |
| 데이터 영역 | 전역 변수, static 변수 저장 |
| 힙 영역 | 동적 할당되는 메모리 (예: new, malloc) |
| 스택 영역 | 함수 호출, 지역 변수 저장 |
각 프로세스는 이 메모리 구조를 독립적으로 가지므로 서로 침범할 수 없다.
✅ 2. 스레드 (Thread)
2.1 정의
스레드는 프로세스 내에서 실행 흐름의 최소 단위이며,
같은 프로세스 내 자원을 공유하면서 독립적으로 실행되는 흐름이다.
2.2 특징
- 하나의 프로세스 안에 여러 개의 스레드가 있을 수 있다.
- 코드, 데이터, 힙은 공유하지만, 스택은 각각 따로 사용한다.
- 스레드는 생성/종료 비용이 낮고, 전환 속도도 빠르다.
스레드를 사용하면 한 프로그램 내에서 여러 작업을 동시에 할 수 있다 (예: 채팅 앱에서 메시지 수신과 입력을 동시에 처리).
2.3 단일 스레드 vs 멀티 스레드
| 구분 | 단일 스레드 | 멀티 스레드 |
|---|---|---|
| 실행 흐름 | 1개 | 여러 개 |
| 속도 | 상대적으로 느림 | 병렬 처리 가능 |
| 자원 공유 | 불필요 | 자원 공유 필요 (주의: 충돌 가능) |
✅ 3. 프로세스와 스레드의 비교
| 항목 | 프로세스 | 스레드 |
|---|---|---|
| 정의 | 실행 중인 프로그램 | 프로세스 내 실행 단위 |
| 메모리 | 독립된 메모리 공간 | 코드, 데이터, 힙 공유, 스택은 분리 |
| 생성 비용 | 높음 | 낮음 |
| 문맥 교환 비용 | 높음 | 낮음 |
| 오류 전파 | 서로 독립적 | 한 스레드 오류 → 전체 프로세스에 영향 가능 |
프로세스는 완전히 독립적인 실행 단위이고,
스레드는 협력적으로 일하는 작은 실행 단위로 이해하면 된다.
⚙️ 운영체제 – 문맥 교환과 스케줄링
운영체제는 여러 프로그램이 동시에 실행되는 환경에서
CPU를 효율적으로 배분하고 관리하는 역할을 한다.
그 핵심 메커니즘이 문맥 교환(Context Switching) 과 스케줄링(Scheduling) 이다.
✅ 1. 문맥 교환 (Context Switching)
1.1 정의
문맥 교환은 CPU가 현재 실행 중인 프로세스나 스레드의 상태를 저장하고,
다른 작업으로 전환하는 과정이다.
1.2 왜 필요한가?
- 컴퓨터는 한 번에 하나의 작업만 수행할 수 있기 때문에
여러 작업(프로세스/스레드)을 빠르게 번갈아 가며 실행해야 한다.
이 때 “지금 하던 작업을 멈추고, 다음 작업을 이어서 하기 위해 상태를 저장하고 불러오는 과정”이 문맥 교환이다.
1.3 포함되는 정보
| 항목 | 설명 |
|---|---|
| 레지스터 값 | 연산 중이던 데이터, 주소 등 |
| 프로그램 카운터 | 다음에 실행할 명령어 위치 |
| 스택 포인터 | 함수 호출 시 사용된 스택 정보 |
| CPU 상태 | 제어 플래그, 인터럽트 설정 등 |
이 정보들은 운영체제가 프로세스마다 갖고 있는 PCB (Process Control Block) 에 저장된다.
1.4 단점
- 문맥 교환 자체가 오버헤드(비용)가 크다.
- 스레드 간 전환은 비용이 낮지만, 프로세스 간 전환은 많은 상태 정보를 저장/복원해야 하므로 상대적으로 느리다.
✅ 2. CPU 스케줄링 (Scheduling)
2.1 정의
스케줄링은 운영체제가 어떤 작업에 CPU를 먼저 줄 것인지 결정하는 정책과 메커니즘이다.
2.2 선점형 vs 비선점형
| 유형 | 설명 |
|---|---|
| 선점형 (Preemptive) | 실행 중이던 작업을 강제로 중단하고 다른 작업으로 전환 가능 |
| 비선점형 (Non-preemptive) | 실행 중인 작업이 스스로 종료하거나 대기 상태가 되기 전까지 계속 실행됨 |
대부분의 현대 운영체제는 선점형을 사용한다.
사용자 반응성을 높이고, 중요한 작업을 빠르게 처리하기 위해 필요하다.
2.3 주요 스케줄링 알고리즘
| 이름 | 특징 |
|---|---|
| FCFS (First Come First Served) | 먼저 도착한 작업부터 실행 |
| SJF (Shortest Job First) | 실행 시간이 가장 짧은 작업부터 |
| Round Robin (RR) | 일정 시간(퀀텀)마다 교체 |
| Priority Scheduling | 우선순위가 높은 작업부터 실행 |
운영체제는 위 알고리즘들을 상황에 따라 혼합하여 사용하기도 한다.
2.4 시분할 시스템에서의 사용
- Round Robin은 대표적인 시분할(Time-sharing) 스케줄링 방식이다.
- 모든 작업에 공정한 CPU 사용 기회를 보장한다.
퀀텀(Quantum): 작업 하나가 CPU를 차지할 수 있는 시간 조각
⚙️ 운영체제 – 동기화: 뮤텍스, 세마포어, 모니터
멀티스레드 환경에서는 여러 작업이 동시에 같은 자원에 접근하려 할 때 충돌이 발생할 수 있다.
이러한 문제를 막고 안전하게 처리하기 위한 기술이 동기화(Synchronization) 이다.
✅ 1. 동기화란?
1.1 정의
동기화는 여러 작업이 동시에 실행될 때,
데이터의 일관성과 안전성을 보장하는 기법이다.
1.2 왜 필요한가?
- 두 개 이상의 스레드가 공유 자원(예: 전역 변수, 파일)에 동시에 접근하면
예기치 않은 결과나 충돌이 발생할 수 있다.
예: 은행 계좌 잔액을 동시에 업데이트하는 두 스레드가 값을 덮어쓰면 잘못된 금액이 저장될 수 있다.
✅ 2. 뮤텍스 (Mutex)
2.1 정의
뮤텍스는 한 번에 하나의 스레드만 자원에 접근할 수 있게 하는 잠금 장치이다.
2.2 특징
- 공유 자원 앞에 자물쇠를 거는 방식
- 자원을 사용하려면 먼저 잠금을 획득(lock)해야 하며,
사용이 끝나면 잠금을 해제(unlock)해야 한다.
뮤텍스는 상호 배제(mutual exclusion)의 줄임말이다.
2.3 사용 흐름
- 스레드가 자원을 요청 → 잠금이 열려 있으면 획득
- 다른 스레드는 잠금이 해제될 때까지 대기
- 작업이 끝난 스레드는 잠금을 해제
- 다음 스레드가 자원 접근
✅ 3. 세마포어 (Semaphore)
3.1 정의
세마포어는 동시에 접근 가능한 스레드 수를 제한하는 동기화 도구다.
3.2 특징
- 내부에 숫자 값(카운터)을 가지고 있음
- 카운터가 0보다 크면 접근 허용, 아니면 대기
- 뮤텍스는 세마포어의 일종 (카운터 = 1)
3.3 종류
| 유형 | 설명 |
|---|---|
| Binary Semaphore | 값이 0 또는 1인 세마포어 (뮤텍스와 유사) |
| Counting Semaphore | 값이 2 이상일 수 있어 다수의 접근 허용 가능 |
세마포어는 공유 자원 수량 제어에 효과적이다.
예: 연결 가능한 데이터베이스 수가 10개면 세마포어 카운터 = 10
✅ 4. 모니터 (Monitor)
4.1 정의
모니터는 데이터 + 동기화 방법(코드)를 하나로 감싼 고급 구조다.
4.2 특징
- 내부의 공유 자원은 한 번에 하나의 스레드만 접근 가능
- 자동으로 lock/unlock을 처리 (언어에 내장된 경우 많음)
자바의
synchronized, 파이썬의with threading.Lock()등이 모니터 개념을 반영한다.
✅ 5. 교착 상태 (Deadlock)
5.1 정의
두 개 이상의 작업이 서로 자원을 점유한 채,
상대방의 자원을 기다리면서 무한히 멈춰 있는 상태
5.2 발생 조건 (4가지가 동시에 만족)
- 상호 배제(Mutual Exclusion): 자원은 한 번에 하나의 작업만 사용 가능
- 점유와 대기(Hold and Wait): 자원을 점유한 채 다른 자원을 기다림
- 비선점(No Preemption): 자원을 강제로 뺏을 수 없음
- 순환 대기(Circular Wait): 작업들이 원형으로 자원을 기다림
이 4가지 중 하나라도 없애면 교착 상태를 방지할 수 있다.
⚙️ 운영체제 – 데드락과 해결 방법
멀티 프로세스나 멀티 스레드 환경에서는 여러 작업이 동시에 자원을 사용하다가
서로 자원을 기다리면서 무한히 멈춰버리는 상황이 발생할 수 있다.
이런 상태를 데드락(Deadlock)이라고 한다.
✅ 1. 데드락이란?
1.1 정의
데드락은 두 개 이상의 작업이 서로가 가진 자원을 끝없이 기다리며 멈춰버리는 상태를 말한다.
예:
스레드 A는 프린터를 가지고 있고, 스캐너가 필요함
스레드 B는 스캐너를 가지고 있고, 프린터가 필요함
→ 둘 다 상대방 자원을 기다리면서 영원히 대기
1.2 발생 조건 (4가지가 모두 만족될 때)
| 조건 | 설명 |
|---|---|
| 상호 배제 | 한 자원은 한 작업만 사용할 수 있음 |
| 점유와 대기 | 자원을 점유한 채 다른 자원을 기다림 |
| 비선점 | 점유한 자원을 강제로 뺏을 수 없음 |
| 순환 대기 | 작업들이 원형으로 자원을 서로 기다림 |
이 4가지 중 하나라도 깨지면 데드락은 발생하지 않는다.
✅ 2. 데드락의 해결 방법
2.1 예방 (Prevention)
아예 데드락 조건 중 하나를 미리 막아버리는 방식
예시 전략
- 점유와 대기 방지: 작업이 필요한 모든 자원을 한 번에 요청하게 강제
- 순환 대기 방지: 자원에 번호를 매기고 순서대로만 요청하게 함
예방은 비교적 단순하지만, 자원 낭비나 비효율을 초래할 수 있음
2.2 회피 (Avoidance)
데드락이 발생할 수 있는 상태에 들어가지 않도록 조심해서 실행
- 가장 대표적인 알고리즘: 은행가 알고리즘(Banker’s Algorithm)
→ 자원을 할당하기 전에 시스템이 안전한 상태인지 시뮬레이션
회피는 더 똑똑한 방식이지만 구현이 복잡하고 비용이 큼
2.3 발견 (Detection)과 복구 (Recovery)
데드락이 실제로 발생했는지 검사하고,
발견되면 해결하는 방식
방법
- 자원 할당 그래프를 분석하여 순환이 존재하는지 확인
- 데드락이 발견되면:
- 프로세스 강제 종료
- 자원 강제 회수 후 재시도
발견 후 복구 방식은 시스템에 충격이 클 수 있으므로 주의가 필요함
2.4 무시 (Ignore)
현실적으로 드물게 발생하고, 처리 비용이 높으면 “무시 전략”을 사용
- 대표 예: Unix, Linux, Windows는 데드락을 방지하지 않음
- 발생 시 사용자가 직접 프로세스를 종료함
이 방법은 시스템이 복잡하거나 성능 우선일 때 사용되지만, 안정성에 취약하다.
⚙️ 운영체제 – 가상 메모리와 페이지 교체 알고리즘
컴퓨터의 실제 메모리(RAM)는 한정되어 있기 때문에
모든 프로그램을 동시에 메모리에 올려놓기는 어렵다.
이를 해결하기 위한 핵심 기술이 바로 가상 메모리(Virtual Memory)다.
✅ 1. 가상 메모리 (Virtual Memory)
1.1 정의
가상 메모리는 물리 메모리보다 더 큰 메모리 공간을 사용하는 것처럼
프로그램을 실행할 수 있도록 만들어주는 기술이다.
실제로는 디스크(보조기억장치)를 이용하여
일부만 메모리에 올리고, 나머지는 필요할 때 가져온다.
1.2 동작 방식
- 프로그램은 자신이 큰 메모리를 모두 사용하는 것처럼 착각한다.
- 운영체제가 필요한 부분만 메모리에 올리고, 나머지는 디스크에 저장한다.
- 메모리에 없는 데이터를 접근하려 하면 → 페이지 폴트(Page Fault) 발생
- 디스크에서 해당 데이터를 불러와 메모리에 올림
1.3 주소 변환
| 주소 | 설명 |
|---|---|
| 가상 주소 | 프로그램이 사용하는 주소 |
| 물리 주소 | 실제 RAM의 주소 |
가상 주소는 페이지 단위로 나눠지며,
운영체제는 이를 물리 주소로 변환해준다.
페이지: 메모리를 관리하기 위해 일정 크기(보통 4KB)로 나눈 단위
✅ 2. 페이지 교체 알고리즘
2.1 필요성
메모리가 가득 찼을 때, 새로운 데이터를 불러오려면
기존 페이지 중 하나를 제거하고 교체해야 한다.
어떤 페이지를 제거할지를 결정하는 정책이 바로 페이지 교체 알고리즘이다.
2.2 주요 알고리즘
| 이름 | 설명 |
|---|---|
| FIFO (First In First Out) | 가장 먼저 들어온 페이지를 제거 |
| LRU (Least Recently Used) | 가장 오랫동안 사용되지 않은 페이지 제거 |
| LFU (Least Frequently Used) | 사용 횟수가 가장 적은 페이지 제거 |
| Optimal | 앞으로 가장 오래 사용되지 않을 페이지 제거 (이론상 최적) |
FIFO는 구현이 쉬우나 성능이 낮고,
LRU는 현실적으로 가장 많이 사용된다.
2.3 페이지 폴트
메모리에 존재하지 않는 페이지에 접근하려고 할 때 발생하는 현상
- 디스크에서 해당 페이지를 읽어 메모리에 올려야 하므로 속도가 매우 느림
- 페이지 교체 알고리즘은 페이지 폴트를 최소화하는 것이 목표다
⚙️ 운영체제 – 파일 시스템과 I/O 시스템
운영체제는 사용자와 저장장치 사이에서 데이터를 안전하고 효율적으로 저장하고 읽을 수 있게 해준다.
이를 담당하는 핵심 구조가 파일 시스템(File System)과 입출력 시스템(I/O System)이다.
✅ 1. 파일 시스템 (File System)
1.1 정의
파일 시스템은 데이터를 파일 단위로 저장하고 관리하는 운영체제의 구성 요소다.
1.2 역할
- 데이터를 논리적으로 분할하고 구조화된 형태(파일, 폴더)로 저장
- 파일의 이름, 위치, 크기, 접근 권한 등을 추적 및 관리
- 사용자, 응용 프로그램, 하드웨어 간 데이터 접근을 중재
1.3 주요 구성 요소
| 구성 요소 | 설명 |
|---|---|
| 파일 | 데이터를 저장하는 기본 단위 |
| 디렉터리 | 파일을 분류하고 정리하는 계층 구조 |
| inode (유닉스) | 파일의 메타데이터를 저장하는 구조 |
| FAT / NTFS / ext4 | 실제 파일 시스템 포맷 (운영체제별로 다름) |
inode: 파일의 이름을 제외한 모든 정보(크기, 위치, 권한 등)를 가지고 있는 데이터 구조
1.4 파일 할당 방식
| 방식 | 설명 |
|---|---|
| 연속 할당 | 연속된 공간에 저장 (빠르지만 공간 낭비 우려) |
| 연결 할당 | 파일을 조각내어 저장, 포인터로 연결 |
| 인덱스 할당 | 인덱스 블록에 모든 블록 주소를 저장 (가장 일반적) |
✅ 2. I/O 시스템 (입출력 시스템)
2.1 정의
I/O 시스템은 운영체제가 저장장치, 네트워크, 키보드, 마우스 등 다양한 장치와 데이터를 주고받는 시스템 구성이다.
2.2 역할
- 다양한 입출력 장치를 통일된 방식으로 다룰 수 있도록 추상화
- 드라이버(driver)를 통해 장치와 운영체제 간 통신을 담당
- 버퍼링, 캐싱, 스풀링 등의 기술로 I/O 효율을 높임
드라이버: 특정 하드웨어 장치를 제어할 수 있도록 해주는 소프트웨어
2.3 입출력 동작 방식
| 방식 | 설명 |
|---|---|
| 프로그램 직접 제어 | CPU가 입출력을 직접 제어 (비효율적) |
| 인터럽트 기반 | 장치가 준비되었을 때만 CPU에게 알려줌 |
| DMA (Direct Memory Access) | 장치가 CPU 도움 없이 메모리와 직접 데이터 주고받음 |
DMA는 CPU의 개입 없이 데이터를 빠르게 전달할 수 있어 고속 장치에서 중요하게 사용된다.
2.4 I/O 최적화 기법
| 기법 | 설명 |
|---|---|
| 버퍼링 | 중간 임시 저장소를 통해 처리 속도 차이를 완충 |
| 캐싱 | 자주 쓰는 데이터를 임시로 저장해 빠르게 접근 |
| 스풀링 | 프린터처럼 순차 처리가 필요한 장치에 대기열 생성 |
스풀링(spooling)은 “일감 예약”처럼 생각하면 된다. 인쇄할 파일을 먼저 줄 세워 놓고 하나씩 보내는 구조
⚙️ 운영체제 – 부팅 과정과 커널 구조
컴퓨터는 전원을 켜는 순간부터 운영체제가 실행되기까지
여러 단계를 거쳐야 한다. 이 과정을 부팅(booting)이라고 하며,
중앙에 있는 핵심 소프트웨어가 바로 커널(Kernel)이다.
✅ 1. 부팅 과정
1.1 정의
부팅이란 컴퓨터에 전원이 켜진 후, 운영체제가 메모리에 적재되어
사용 가능한 상태로 전환되는 일련의 과정이다.
1.2 전체 흐름
- 전원 공급
- 하드웨어 초기화 시작
- BIOS/UEFI 실행
- 하드웨어 장치 점검 (POST), 부트 장치 탐색
BIOS: Basic Input/Output System
UEFI: BIOS의 현대적 버전
- MBR 또는 EFI에서 부트로더 로드
- 운영체제를 메모리에 올리는 작은 프로그램 실행
부트로더: 운영체제를 메모리에 적재하는 역할 (ex: GRUB)
- 운영체제 커널 로딩
- 운영체제의 핵심인 커널을 메모리에 적재
- 시스템 서비스, 드라이버 초기화 → 사용자 환경 제공
1.3 부트로더란?
부트로더는 운영체제를 시작할 수 있도록 도와주는 작은 프로그램이다.
BIOS/UEFI가 하드디스크에서 부트로더를 찾아 실행시킨다.
✅ 2. 커널 (Kernel)
2.1 정의
커널은 운영체제의 핵심으로,
하드웨어와 사용자 프로그램 사이를 중재하는 핵심 소프트웨어이다.
운영체제의 가장 중심에 위치하며, 모든 자원 관리와 시스템 호출을 처리한다.
2.2 역할
| 기능 | 설명 |
|---|---|
| 프로세스 관리 | 작업 생성, 삭제, 스케줄링 |
| 메모리 관리 | RAM 할당, 가상 메모리 구성 |
| 파일 시스템 관리 | 파일 접근, 디렉터리 관리 |
| 장치 드라이버 관리 | 입출력 장치 제어 |
| 시스템 콜 처리 | 사용자 프로그램의 요청을 커널이 수행 |
2.3 커널의 종류
| 종류 | 설명 |
|---|---|
| 모놀리식 커널 | 커널이 모든 기능을 하나로 포함 (ex: Linux) |
| 마이크로커널 | 핵심 기능만 커널에 넣고 나머지는 외부 프로세스로 분리 |
| 하이브리드 커널 | 위 두 방식을 절충 (ex: Windows NT) |
마이크로커널은 안정성이 높지만 성능이 떨어질 수 있고,
모놀리식은 성능은 좋지만 안정성 측면에서 복잡도가 높다.
2.4 시스템 콜이란?
시스템 콜(System Call)은 사용자 프로그램이 커널에게 작업을 요청하는 창구다.
예: 파일 열기, 메모리 할당, 프로세스 생성 등