운영체제와 하드웨어

낚시하는 곰·2025년 3월 20일

krafton jungle

목록 보기
18/52

응용 프로그램이 운영체제를 통해 하드웨어를 제어하는 원리

응용 프로그램 → 운영체제 → 하드웨어 순으로 동작하며, 이 과정에서 운영체제가 하드웨어와의 직접적인 인터페이스를 담당한다.

┌───────────────────────┐
│ 응용 프로그램 (App)   │  ← 사용자가 직접 실행 (ex: 게임, 웹브라우저, DB)
└───────────────────────┘
         ⬇   
┌───────────────────────┐
│ 운영체제 (OS)        │  ← 응용 프로그램과 하드웨어 사이의 인터페이스
│  - 시스템 콜 (System Call) │
│  - 드라이버 (Device Driver) │
└───────────────────────┘
         ⬇
┌───────────────────────┐
│ 하드웨어 (Hardware)   │  ← CPU, 메모리, 디스크, 네트워크 등
└───────────────────────┘

시스템 콜

  • 응용 프로그램이 운영체제에게 서비스를 요청하는 인터페이스
  • 응용 프로그램이 직접 하드웨어를 다룰 수 없으므로, 운영체제에 특정 기능을 요청해야 한다.
    이를 위해 제공되는 기능이 시스템 콜(System Call) 이다.
응용 프로그램 (텍스트 편집기) → 시스템 콜 open() 요청 → 운영체제 → 하드웨어에서 파일 읽기

운영체제에서 제공하는 주요 시스템 콜

파일 처리: open(), read(), write(), close()
프로세스 관리: fork(), exec(), wait()
메모리 관리: malloc(), mmap()
네트워크 처리: socket(), connect()
입출력(IO): ioctl()

역할

  • 응용 프로그램이 직접 하드웨어를 접근하지 않고 OS를 통해 사용
  • 운영체제가 하드웨어 리소스를 안전하게 관리할 수 있도록 함
  • 하드웨어 종류가 달라도 동일한 시스템 콜을 사용하여 프로그램 호환성 유지

드라이버

  • 운영체제가 하드웨어를 제어하기 위해 제공하는 소프트웨어
  • 운영체제는 하드웨어마다 적절한 드라이버를 로드하여 해당 장치를 제어한다.
  • 운영체제와 하드웨어 간의 통신 인터페이스 제공
  • 응용 프로그램이 하드웨어의 세부사항을 몰라도 사용할 수 있도록 추상화
  • 하드웨어 종류에 따라 필요한 명령어를 변환하여 실행
1. USB를 컴퓨터에 연결
2. 운영체제가 USB 드라이버 로드
3. 응용 프로그램에서 USB 파일을 읽기 요청
4. 운영체제가 드라이버를 통해 USB 장치와 통신
5. 파일을 응용 프로그램에 전달

커널

  • 운영체제의 핵심 부분으로, 하드웨어와 직접 상호작용하는 역할
  • 커널(Kernel)은 운영체제의 핵심이며, 모든 하드웨어 리소스를 관리한다.
  • 응용 프로그램이 요청하면 커널이 시스템 콜을 통해 하드웨어에 명령을 전달한다.

역할

  • 응용 프로그램이 하드웨어 세부사항을 몰라도 동작할 수 있도록 도와줌
  • CPU, 메모리, 스토리지 등 시스템 리소스를 안전하게 관리
  • 멀티태스킹 환경에서 여러 프로그램을 동시에 실행 가능

응용 프로그램이 파일을 읽는 과정

1. 응용 프로그램: "파일을 읽어야 해!" → `open("data.txt")` 실행
2. 운영체제 (커널): 시스템 콜(`open()`)을 통해 요청 확인
3. 운영체제: 파일 시스템 드라이버를 통해 HDD/SSD에서 "data.txt" 파일 검색
4. 하드웨어: HDD/SSD에서 해당 파일의 데이터를 RAM으로 로드
5. 운영체제: 응용 프로그램에 파일 내용을 반환

캐보드 입력이 응용 프로그램에 전달 되는 과정

1. 사용자가 키보드에서 "A" 입력
2. 키보드 드라이버가 인터럽트 발생 (하드웨어 → 운영체제)
3. 운영체제는 키 입력을 처리하고, 해당 데이터를 응용 프로그램에 전달
4. 응용 프로그램(텍스트 편집기)이 "A"를 화면에 출력

운영체제의 커널을 수정하거나 드라이버를 변경하면 하드웨어의 동작을 다르게 제어할 수 있을까?

커널 수정

💡 커널은 운영체제의 핵심이며, 하드웨어와 직접 상호작용하는 역할
👉 커널을 수정하면 프로세스 관리, 파일 시스템, 메모리 관리, 입출력(IO) 방식 등을 변경할 수 있다.

📌 커널 수정 예시

  • CPU 스케줄링 알고리즘 변경 → 특정 프로세스를 우선적으로 실행
  • 메모리 관리 방식 변경 → 특정 프로그램이 더 많은 RAM을 사용하도록 설정
  • 파일 시스템 수정 → 새로운 방식의 파일 저장 시스템 구현

디바이스 드라이버 수정

💡 드라이버는 운영체제가 하드웨어를 조작하는 중간 다리 역할
👉 드라이버를 수정하면, 키보드, 마우스, GPU, 네트워크 장치 등의 동작을 변경할 수 있다.

📌 드라이버 수정 예시

  • 그래픽 카드 드라이버 수정 → GPU의 클럭 속도를 조절하여 오버클럭/언더클럭 가능
  • USB 포트 제어 → 특정 장치만 허용하고 나머지는 차단
  • 마우스, 키보드 입력 수정 → 특정 키 입력을 다른 키로 매핑

시스템 콜 수정

💡 시스템 콜은 응용 프로그램이 운영체제에게 특정 기능을 요청하는 인터페이스
👉 시스템 콜을 수정하면 응용 프로그램이 하드웨어를 다루는 방식을 변경할 수 있다.

📌 시스템 콜 수정 예시

  • 파일 접근 방식 변경 → open(), read(), write()를 수정하여 특정 파일 접근 차단
  • 프로세스 실행 제한 → fork(), exec()를 수정하여 특정 프로그램 실행을 차단
  • 네트워크 트래픽 변경 → socket() 호출을 수정하여 네트워크 통신을 감시

프로세스

프로세스란?

프로세스(Process) 는 실행 중인 프로그램(Executable Code + 실행 상태) 을 의미한다.
즉, 하드디스크나 SSD에 저장된 프로그램 파일이 운영체제(OS)에 의해 메모리(RAM)로 로드되어 실행되는 개체를 프로세스라고 한다.

프로세스의 특징

✅ 독립적인 실행 단위

  • 각 프로세스는 자신만의 메모리 공간을 가지며, 독립적으로 실행된다.
  • 하나의 프로그램은 여러 개의 프로세스를 생성할 수도 있다.

✅ 운영체제에 의해 관리됨

  • 운영체제(OS)는 프로세스를 생성하고, CPU를 할당하고, 메모리와 입출력을 관리한다.
  • 각 프로세스는 PID(Process ID) 라는 고유한 식별자를 가진다.

✅ 멀티태스킹 지원

  • 현대 운영체제는 여러 프로세스를 동시에 실행(멀티태스킹)할 수 있도록 한다.

✅ 동기 & 비동기 실행 가능

  • 프로세스는 다른 프로세스와 동기(Synchronous) 또는 비동기(Asynchronous) 방식으로 실행될 수 있다.

프로그램과 프로세스의 차이

프로그램은 실행되기 전의 코드 파일이고, 프로세스는 실제로 실행되고 있는 개체이다.

프로세스의 생애주기

[New] → [Ready] → [Running] → [Waiting] → [Terminated]

프로세스는 CPU를 사용하기 위해 Ready → Running 상태로 전환되며, 실행 중에 I/O 요청이 발생하면 Waiting 상태로 이동한다.

프로세스의 메모리 구조

┌─────────────────┐
│ Stack (스택)    │  지역 변수, 함수 호출 정보 (LIFO 구조)
├─────────────────┤
│ Heap (힙)       │  동적 메모리 할당 (`malloc()`, `new`)
├─────────────────┤
│ Data (데이터)   │  전역 변수, static 변수 저장
├─────────────────┤
│ Code (코드)     │  실행할 프로그램의 코드 (CPU 명령어)
└─────────────────┘

✅ Stack (스택): 함수 호출 시 생성되는 지역 변수 저장
✅ Heap (힙): 실행 중 동적으로 할당되는 메모리 영역
✅ Data (데이터): 프로그램이 사용하는 전역 변수 저장
✅ Code (코드): 실행 파일의 명령어(코드)가 저장됨

👉 이처럼 프로세스마다 독립적인 메모리 공간을 가지기 때문에, 한 프로세스가 다른 프로세스의 메모리를 직접 수정할 수 없다.
👉 프로세스 간 데이터를 주고받으려면 IPC(Inter-Process Communication) 기법을 사용해야 한다.

프로세스 스케줄링

운영체제는 여러 프로세스를 동시에 실행할 수 있도록 CPU 스케줄러를 사용하여 프로세스를 관리한다.

✅ 선점형 스케줄링 (Preemptive Scheduling)

한 프로세스가 실행 중이어도, 운영체제가 강제로 CPU를 빼앗아 다른 프로세스에 할당할 수 있음.
Round Robin, Priority Scheduling, Multilevel Queue 방식이 있음.

✅ 비선점형 스케줄링 (Non-Preemptive Scheduling)

한 프로세스가 실행을 마칠 때까지 CPU를 유지함.
FCFS (First Come First Serve), SJF (Shortest Job First) 방식이 있음.

👉 운영체제는 CPU 시간을 효율적으로 배분하여, 여러 프로세스가 동시에 실행될 수 있도록 한다.

프로세스 간 통신

프로세스는 각각 독립적인 메모리 공간을 가지므로, 데이터를 공유하려면 스 간 통신) 방법을 사용해야 한다.

프로세스 간 통신 흐름

프로세스 간 통신(IPC, Inter-Process Communication) 의 흐름은 다음과 같이 진행된다.
즉, 한 프로세스가 데이터를 생성하고, 이를 운영체제를 통해 다른 프로세스로 전달하는 과정이 포함된다.

┌───────────────┐      ┌───────────────┐
│ Process A (Sender) │  →  │ Process B (Receiver) │
│  (데이터 생성)      │      │  (데이터 수신)      │
└───────────────┘      └───────────────┘
          ↘                 ↙
          운영체제(OS) → (데이터 관리)

📌 기본적인 흐름
1️⃣ 프로세스 A (발신자)에서 데이터 생성
2️⃣ 운영체제(OS)가 데이터 전달 중개
3️⃣ 프로세스 B (수신자)에서 데이터 수신

이 과정에서 운영체제는 메모리를 보호하면서 데이터를 안전하게 교환하도록 IPC 기법을 제공한다.

✅ (1) 파이프(Pipe) 방식의 흐름

💡 한 프로세스의 출력이 다른 프로세스의 입력으로 연결되는 방식

  • 주로 부모-자식 프로세스 간의 통신에서 사용됨.
Process A (Writer)  →  Pipe  →  Process B (Reader)

📌 흐름
1️⃣ Process A가 Pipe를 생성
2️⃣ 데이터를 Pipe에 쓰기 (write)
3️⃣ Process B가 Pipe에서 데이터를 읽기 (read)
4️⃣ 데이터가 전달되면 Pipe는 자동 삭제됨

사용 예시

  • 리눅스 명령어에서 ls | grep txt
  • ls(Process A)의 출력이 grep(Process B)의 입력으로 전달됨

✅ (2) 메시지 큐(Message Queue) 방식의 흐름

💡 운영체제가 관리하는 메시지 큐를 사용하여 데이터를 주고받는 방식

  • 비동기식 통신이 가능 (보내는 쪽과 받는 쪽이 동시에 실행될 필요 없음).
Process A (Sender) → Message Queue → Process B (Receiver)

📌 흐름
1️⃣ Process A가 Message Queue를 생성
2️⃣ Process A가 큐에 메시지를 쓰기 (send message)
3️⃣ Process B가 메시지를 큐에서 읽기 (receive message)
4️⃣ 운영체제가 큐를 통해 메시지를 관리

사용 예시

  • 클라이언트-서버 모델에서 비동기 요청 처리
  • RabbitMQ, Kafka 같은 메시지 브로커 시스템

✅ (3) 공유 메모리(Shared Memory) 방식의 흐름

💡 프로세스들이 같은 메모리 공간을 공유하여 데이터를 직접 주고받는 방식

  • 가장 빠른 IPC 방식이지만, 동기화 기법(뮤텍스, 세마포어)이 필요
Process A  →  Shared Memory  →  Process B

📌 흐름
1️⃣ Process A가 공유 메모리 공간을 생성
2️⃣ Process A가 데이터를 메모리에 저장
3️⃣ Process B가 같은 메모리를 읽어서 데이터 수신
4️⃣ 데이터가 유지되며 여러 프로세스가 접근 가능

사용 예시

  • 데이터베이스 관리 시스템(DBMS)
  • 고속 데이터 처리가 필요한 애플리케이션

⚠️ 주의할 점:

  • 여러 프로세스가 동시에 접근하면 데이터 충돌이 발생할 수 있음뮤텍스(Mutex) 또는 세마포어(Semaphore) 사용 필요

✅ (4) 소켓(Socket) 방식의 흐름

💡 네트워크를 통해 프로세스 간 데이터를 주고받는 방식

  • 원격 프로세스 간 통신이 가능 (예: 클라이언트-서버 모델)
Client Process → Socket → Server Process

📌 흐름
1️⃣ 클라이언트 프로세스가 소켓을 생성하여 서버에 연결 요청
2️⃣ 서버 프로세스가 클라이언트의 요청을 수락
3️⃣ 클라이언트와 서버가 소켓을 통해 데이터 송수신
4️⃣ 연결이 끝나면 소켓을 닫음 (close)

사용 예시

  • 웹 서버와 클라이언트 간 HTTP 통신
  • 온라인 게임에서 실시간 데이터 동기화

운영체제와 프로세서 간의 동작 원리

운영체제(OS)와 프로세서(CPU)는 서로 협력하여 프로그램을 실행한다.
전체적인 동작 과정은 프로그램 실행 → 프로세스 생성 → CPU 스케줄링 → 명령어 처리 → 인터럽트 관리 순서로 진행된다.

1. 프로그램 실행 요청
2. 운영체제(OS)가 프로그램을 프로세스로 생성
3. 운영체제가 프로세스를 CPU 스케줄링 (Ready → Running)
4. CPU가 명령어를 가져와(페치) 실행
5. CPU가 메모리, 입출력(I/O) 요청을 수행
6. 프로세스가 종료되거나, 다른 프로세스로 교체(Context Switching)
7. 운영체제가 프로세스를 정리하고 자원을 반환

📌 1. 프로그램 실행 요청

  • 사용자가 프로그램을 실행하면 운영체제는 해당 프로그램을 프로세스로 변환하여 실행한다.
  • 프로그램은 디스크(HDD/SSD)에 저장되어 있으며, 실행을 위해 메모리(RAM)로 로드된다.
사용자: "크롬 브라우저 실행"
↓
운영체제: "chrome.exe 프로그램을 실행할 준비 완료!"
↓
프로그램을 프로세스로 변환

📌 2. 운영체제(OS)가 프로그램을 프로세스로 생성

운영체제는 프로그램을 실행하기 위해 프로세스를 생성(Process Creation) 한다.
이 과정에서 운영체제는 다음과 같은 작업을 수행한다.

필요한 리소스 할당:

  • 메모리(RAM) 공간 확보
  • 파일 핸들(File Handle) 할당
  • 프로세스 ID(PID) 부여
  • CPU 실행 준비
운영체제:
1. 프로세스를 생성하고 고유한 PID(Process ID) 부여
2. 프로그램 실행 코드를 메모리에 로드
3. 프로세스를 Ready 상태로 변경 (CPU 실행 대기)

📌 예제: 크롬 브라우저 실행

chrome.exe → Process A (PID: 1001) 생성

📌 3. 운영체제가 프로세스를 CPU 스케줄링

운영체제는 여러 개의 프로세스를 관리하며, CPU가 어떤 프로세스를 실행할지 결정한다.
이 과정에서 스케줄러(Scheduler) 가 작동한다.

CPU 스케줄링 단계
1. Ready Queue 에 있는 프로세스 중 하나를 선택
2. CPU 할당 (Running 상태로 변경)
3. 일정 시간이 지나면 다른 프로세스로 교체 (Context Switching 발생)

운영체제:
1. 현재 실행 가능한 프로세스 목록 확인 (Ready Queue)
2. 스케줄링 알고리즘(FIFO, Round Robin 등)을 사용하여 실행할 프로세스 결정
3. 선택된 프로세스에 CPU 할당 (Ready → Running)

📌 예제: 크롬 브라우저가 실행되기 위한 CPU 스케줄링

[Ready Queue]
1. Chrome.exe (PID 1001)
2. VSCode.exe (PID 1002)
3. Spotify.exe (PID 1003)

운영체제:
→ Chrome.exe (PID 1001) 실행!

📌 4. CPU가 명령어를 가져와(페치) 실행

CPU는 실행 중인 프로세스의 명령어를 하나씩 가져와 실행(Fetch-Decode-Execute) 한다.

CPU 명령어 실행 과정
1. Fetch (명령어 가져오기) → 명령어를 메모리에서 읽어옴
2. Decode (명령어 해석) → CPU가 명령어를 해석
3. Execute (명령어 실행) → 연산 수행, 결과 저장
4. Write-back (결과 저장) → 연산 결과를 레지스터 또는 메모리에 저장

1. CPU: "다음 명령어를 메모리에서 가져와!"
2. CPU: "명령어 해석 중..."
3. CPU: "명령어 실행 완료!"
4. CPU: "결과를 저장하고 다음 명령어를 실행!"

📌 예제: 크롬에서 웹 페이지 로드

1. CPU가 "페이지 로드" 명령어를 메모리에서 가져옴
2. CPU가 HTML 렌더링 명령어 실행
3. GPU에 렌더링 요청 전달
4. 결과를 화면에 표시

📌 5. CPU가 메모리, 입출력(I/O) 요청 수행

  • 실행 중인 프로세스가 파일을 읽거나, 네트워크 요청을 보내거나, 화면에 출력을 할 때 운영체제는 입출력(I/O) 관리를 수행한다.
  • CPU는 I/O 요청이 완료될 때까지 기다리지 않고 다른 프로세스를 실행(Context Switching) 한다.

입출력 요청 흐름

프로세스: "파일 data.txt를 읽고 싶어!"
↓
운영체제: "디스크에서 data.txt 읽는 중... 기다려!"
↓
CPU는 다른 프로세스를 실행 (Context Switching)
↓
운영체제: "파일 로드 완료!"
↓
프로세스: "파일 데이터를 가져왔어!"

📌 예제: 크롬 브라우저에서 이미지 로드

1. 크롬: "이미지를 다운로드해!"
2. 운영체제: "네트워크 요청 처리 중..."
3. CPU는 다른 프로세스를 실행
4. 다운로드 완료 후 크롬이 다시 실행

📌 6. 프로세스가 종료되거나, 다른 프로세스로 교체(Context Switching)

  • CPU 할당 시간이 끝나거나, 입출력 요청이 발생하면 운영체제는 CPU를 다른 프로세스로 교체(Context Switching)한다.
  • 실행이 완료된 프로세스는 운영체제에 의해 종료(Terminated 상태로 변경) 된다.

Context Switching 과정

1. 현재 실행 중인 프로세스의 상태 저장 (Register, Stack 등)
2. 새로운 프로세스의 상태 불러오기
3. CPU 제어권을 새로운 프로세스에게 넘김

📌 예제: 크롬이 이미지 로드를 기다리는 동안 VSCode 실행

1. 크롬이 네트워크 요청 중 (Waiting 상태)
2. CPU가 VSCode 실행 (Ready → Running)
3. 크롬의 네트워크 요청 완료되면 다시 실행

📌 7. 운영체제가 프로세스를 정리하고 자원을 반환

프로세스가 종료되면 운영체제는 사용했던 메모리, 파일 핸들, 네트워크 연결 등을 반환하여 다른 프로세스가 사용할 수 있도록 한다.

운영체제의 역할

1. 프로세스 상태를 "Terminated"로 변경
2. 사용하던 메모리 공간 해제
3. 파일 핸들 및 네트워크 연결 종료
4. 프로세스 ID(PID) 반환

📌 예제: 크롬 브라우저 종료

1. 사용자가 "Chrome 종료" 클릭
2. 운영체제: "프로세스 종료 중..."
3. 메모리 해제, 파일 닫기, 네트워크 연결 종료
4. 크롬 프로세스 완전히 종료됨

컨텍스트(context)

컨텍스트는 어디에 저장될까?

컨텍스트(Context)란?
컨텍스트는 프로세스가 실행되는 동안의 모든 정보를 의미하며, 일반적으로 다음과 같은 정보를 포함한다.

컨텍스트의 주요 구성 요소

📌 컨텍스트는 운영체제의 "프로세스 제어 블록(PCB, Process Control Block)"에 저장된다.

  • PCB는 운영체제가 프로세스를 관리하기 위해 사용하는 데이터 구조로, 각 프로세스마다 하나씩 존재한다.
  • PCB는 커널 메모리 영역에 저장되며, 사용자 프로세스가 직접 접근할 수 없다.
┌──────────────────────────────────────────────┐
│                운영체제 (OS)                  │
│  ┌────────────────────────────────────────┐  │
│  │           프로세스 테이블               │  │
│  │ ┌──────────────────────────────────┐  │  │
│  │ │  PCB (Process Control Block)     │  │  │
│  │ │  ────────────────                │  │  │
│  │ │  프로세스 ID (PID)               │  │  │
│  │ │  프로세스 상태 (Ready, Running)   │  │  │
│  │ │  프로그램 카운터 (PC)             │  │  │
│  │ │  레지스터 값                      │  │  │
│  │ │  메모리 정보                      │  │  │
│  │ │  스케줄링 정보                    │  │  │
│  │ └──────────────────────────────────┘  │  │
│  │ ┌──────────────────────────────────┐  │  │
│  │ │  PCB (다른 프로세스)              │  │  │
│  │ └──────────────────────────────────┘  │  │
│  └────────────────────────────────────────┘  │
└──────────────────────────────────────────────┘

즉, 현재 실행 중인 프로세스의 모든 상태 정보(컨텍스트)는 "PCB"에 저장된다!


2️⃣ 컨텍스트는 어떻게 복원될까?

💡 컨텍스트가 복원된다는 것은, 이전 프로세스가 중단된 시점부터 다시 실행된다는 의미이다.

컨텍스트 복원의 과정
1️⃣ 운영체제가 PCB에서 저장된 컨텍스트를 가져온다.
2️⃣ CPU 레지스터와 프로그램 카운터를 복원한다.
3️⃣ 이전 프로세스가 실행되던 시점부터 그대로 다시 실행된다.

┌─────────────────────────────────────┐
│    기존 실행 중이던 프로세스 A       │
│    - 프로그램 카운터: 0x0000234A      │
│    - 레지스터 정보: rax=100, rbx=50  │
└─────────────────────────────────────┘
     ↓ 컨텍스트 저장 (PCB에 저장)

┌─────────────────────────────────────┐
│    새로운 프로세스 B 실행            │
│    - 프로그램 카운터: 0x0000789B      │
│    - 레지스터 정보: rax=20, rbx=30   │
└─────────────────────────────────────┘
     ↓ 프로세스 B 실행 종료, 다시 A 실행

┌─────────────────────────────────────┐
│    프로세스 A의 컨텍스트 복원         │
│    - 프로그램 카운터: 0x0000234A      │
│    - 레지스터 정보: rax=100, rbx=50  │
└─────────────────────────────────────┘

즉, 저장된 컨텍스트를 복원하면, 프로세스는 마치 멈춘 적이 없던 것처럼 다시 실행된다!

profile
취업 준비생 낚곰입니다!! 반갑습니다!!

0개의 댓글