운영체제 1주차

운영체제 섹션1

 

1. 운영체제가 하는 일

운영체제(OS, Operating System)는 하드웨어와 소프트웨어 자원을 효율적으로 관리하고 사용자에게 서비스를 제공하는 소프트웨어 계층입니다.

  1. 프로세스 관리

    • 여러 프로그램(프로세스)을 동시에 실행하도록 스케줄링(우선순위 관리 등)

    • 프로세스 간 문맥 교환(Context Switching)자원 할당


  2. 메모리 관리

    • 프로세스에 필요한 메모리 공간을 할당/회수, 가상 메모리 등으로 메모리 활용을 극대화

  3. 하드웨어 관리

    • CPU, 입출력 장치(I/O), 저장장치 등의 자원 할당

    • 디바이스 드라이버를 통해 하드웨어와 통신 중재

  4. 파일 시스템 관리

    • 디스크 등에 파일을 읽고, 쓰고, 삭제 등 수행


2. 운영체제의 구조

  1. 커널(Kernel)

    • 운영체제의 핵심 영역으로, 프로세스 관리, 메모리 관리, 저장장치 관리 등 주요 기능 담당

  2. 인터페이스를 통한 커널 접근

    • GUI: 아이콘, 창, 마우스 등 그래픽 요소로 소통

    • CLI: 터미널에 명령어로 소통 (예: Bash, Powershell 등)

  3. 시스템 콜(System Call)

    • 사용자 프로그램(애플리케이션)이 OS 커널 서비스를 요청하는 인터페이스

    • 예) open(), fork(), socket()

    • (코드 예시)

      #include <unistd.h>
      #include <sys/types.h>
      #include <sys/stat.h>
      #include <fcntl.h>
      
      int main() {
          int fd = open("example.txt", O_RDONLY);  // 시스템 콜을 통해 파일 오픈
          if (fd < 0) {
              // 에러 처리
          }
          // 파일 읽기, 처리 등...
          close(fd);
          return 0;
      }
      

       

  4. 하드웨어 드라이버

    • OS와 실제 하드웨어를 연결하는 소프트웨어

    • 새 하드웨어 인식이나 장치 제어 시 필요


3. 폰 노이만 구조 (Von Neumann Architecture)

  1. 탄생 배경

    • 프로그램마다 하드웨어 배선을 일일이 교체하던 비효율을 개선하고자 등장

    • CPU메모리가 버스로 연결, 프로그램과 데이터를 같은 메모리에 저장

  2. 구성 요소

    • CPU: 산술 논리 연산장치(ALU), 제어 장치(CU), 레지스터

    • 메모리(RAM, ROM), 버스(데이터/주소/제어 버스)

  3. 프로그램 내장 방식

    • 프로그램(기계어 코드)을 메모리에 올린 뒤 CPU가 순차적으로 명령어를 읽어 실행


4. CPU의 처리 방식

  1. 폴링(Polling)

    • CPU가 주기적으로 I/O 완료 여부를 확인하는 방식

    • (코드 예시 / 의사코드)

      while (1) {
          if (device_status == READY) {
              // 처리 로직
          }
          // 다른 작업
      }
      
    • 비효율적일 수 있음

  2. 인터럽트(Interrupt)

    • I/O가 완료되면 하드웨어가 CPU에 신호(Interrupt Request) 전송 -> CPU가 즉시 처리 루틴으로 이동

 

운영체제 섹션2 : 프로세스와 쓰레드

1. 프로그램과 프로세스

  1. 프로그램: 저장장치에 있는 명령어 집합 (정적)

  2. 프로세스: 메모리에 적재되어 실행 중인 프로그램 (동적)

  3. 프로세스 구조

    • 코드 영역: 실행할 명령어

    • 데이터 영역: 전역 변수, 정적 변수

    • 스택 영역: 함수 호출 시 지역 변수, 반환 주소 등

    • 힙 영역: 동적 메모리 할당 영역

  4. 코드가 프로세스가 되는 과정

    • 전처리 → 컴파일 → 링킹 → 실행 파일 생성 → 메모리에 적재 → 프로세스


2. 멀티프로그래밍과 멀티프로세싱

  1. 멀티프로그래밍(Multiprogramming)

    • 메모리에 여러 프로그램을 동시에 올려두고, CPU가 I/O 대기 시 다른 프로그램 실행

  2. 멀티태스킹(Multitasking)

    • CPU 시간을 쪼개서 여러 프로세스를 빠르게 교차 실행 -> 동시에 돌아가는 것처럼 보임

  3. 멀티프로세싱(Multiprocessing)

    • 여러 CPU(코어)가 각각 다른 프로세스를 병렬로 처리


3. PCB (Process Control Block)

  1. 정의

    • 프로세스를 관리하기 위해 운영체제가 사용하는 자료구조

    • 프로세스 식별자, 상태, 레지스터 값, 메모리 정보 등 포함

  2. (ASCII 다이어그램 예시)

    +-----------------------------------+
    |  Process ID (PID) = 1234         |
    |  State = RUNNING                 |
    |  Program Counter = 0x100057      |
    |  CPU Registers = [... ]          |
    |  Memory Info (Base, Limit ...)   |
    |  Open File List, etc.            |
    +-----------------------------------+
    
  3. PCB 관리

    • 프로세스 생성 시 PCB를 만들고, 프로세스 종료 시 PCB를 제거

 

4. 프로세스의 상태

  • 생성(New)준비(Ready)실행(Running)대기(Waiting)완료(Terminated)

     

        +-----+
        | New |      (프로세스 생성 상태)
        +-----+
           |
           |  (OS가 프로세스를 준비 큐로 편입)
           v
        +--------+   (준비 상태; CPU 할당 대기)
        | Ready  | 
        +--------+
           |
           | (CPU 스케줄러가 프로세스에게 CPU 할당)
           v
        +--------+   (실행 상태; CPU를 점유 중)
        |Running |
        +--------+
           |  \
           |   \ (입출력 또는 이벤트가 필요) 
           |    \
           |     v
           |   +--------+   (대기 상태; I/O 완료 등 이벤트를 기다림)
           |   |Waiting |
           |   +--------+
           |       |
           |       | (I/O 혹은 이벤트 완료 시)
           |       v
           |    +--------+
           |    | Ready  |  (다시 CPU 할당 대기 상태로 복귀)
           |    +--------+
           |
           | (프로세스 실행이 종료될 때)
           v
        +-----------+  (완료 상태; 프로세스 종료)
        |Terminated |
        +-----------+

    1. 5. 컨텍스트 스위칭 (Context Switching)

  • 현재 실행 중인 프로세스의 레지스터, PC 등을 PCB에 저장

  • 새롭게 실행할 프로세스의 PCB 정보를 불러와 레지스터, PC 설정

  • 빈번하면 오버헤드(시간 낭비) 증가

// 단순 의사코드
save_state_of(curr_process); // 레지스터, PC -> curr_process.PCB
curr_process.state = READY;

curr_process = next_process_from_ready_queue();
load_state_of(curr_process); // 레지스터, PC <- next_process.PCB
curr_process.state = RUNNING;

6. 프로세스의 생성과 종료

  1. 프로세스 생성

    • 리눅스의 경우 fork() 시스템 콜로 부모 프로세스를 복제

       

      #include <stdio.h>
      #include <unistd.h>
      
      int main() {
          pid_t pid = fork();
          if (pid == 0) {
              // 자식 프로세스
              printf("Child Process: PID=%d\n", getpid());
          } else {
              // 부모 프로세스
              printf("Parent Process: PID=%d, Child PID=%d\n", getpid(), pid);
          }
          return 0;
      }
      
  2. 좀비 프로세스(Zombie)

    • 자식이 종료되었지만 부모가 wait()로 회수하지 않아 PCB가 남아있는 상태

 

7. 쓰레드(Thread)

  1. 등장 배경

    • 탭마다 프로세스를 새로 만들면 자원 낭비

    • 하나의 프로세스 내 여러 실행 흐름(쓰레드)을 사용

  2. 공유 자원

    • 같은 프로세스 내부의 쓰레드들은 코드, 데이터, 힙을 공유하지만 스택은 개별

       

    #include <pthread.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    void* thread_func(void* arg) {
        printf("Thread %ld is running!\n", (long)arg);
        return NULL;
    }
    
    int main() {
        pthread_t threads[2];
        for (long i = 0; i < 2; i++) {
            pthread_create(&threads[i], NULL, thread_func, (void*)i);
        }
        for (int i = 0; i < 2; i++) {
            pthread_join(threads[i], NULL);
        }
        return 0;
    }
    
  3. 프로세스 vs 쓰레드

    • 안정성: 프로세스는 서로 독립, 쓰레드는 한 프로세스 내부 공유

    • 속도/자원: 프로세스 생성/소멸 오버헤드 > 쓰레드 생성/소멸 오버헤드


운영체제 섹션3 : CPU 스케줄링

1. 스케줄링의 개념

  • CPU가 여러 프로세스를 언제, 어떻게 실행할지 결정하는 정책

  • 목표: CPU 활용도 극대화, 공평성, 처리량 극대화, 대기/응답시간 최소화

 

2. 다중큐 (Multi-Queue)

  • 여러 개의 대기열(Queue)을 두고, 우선순위 또는 도착 순서에 따라 프로세스를 배치

  • (이미지 예시)

    • 여러 줄(큐)에 프로세스가 나누어져 있는 그림

    • 예시 이미지 링크


3. 대표적인 CPU 스케줄링 알고리즘

  1. FIFO (First In First Out)

    • 도착 순서대로 CPU 할당

    • 구현은 단순하지만, 긴 작업이 뒤의 작업들을 오래 기다리게 할 수 있음


  2. SJF (Shortest Job First)

    • 실행 시간이 짧은 작업부터 먼저 처리

    • 실제 실행 시간을 미리 알기 어려우며, 긴 작업이 계속 밀릴 위험(Starvation)

  3. RR (Round Robin)

    • Time Slice(할당 시간)만큼 CPU를 할당, 시간 만료 시 다음 프로세스로 전환

       

      while (ready_queue is not empty) {
          process = dequeue(ready_queue)
          run(process, TIME_SLICE)
          if (process not finished) {
              enqueue(ready_queue, process)
          }
      }
      

       

  4. MLFQ (Multi-Level Feedback Queue)

    • 여러 단계(레벨)의 큐를 두고, CPU 사용량에 따라 우선순위를 변경

    • I/O 바운드라면 높은 우선순위 유지, CPU 바운드라면 우선순위가 점점 낮아짐

채널톡 아이콘