ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 운영체제 (1)
    프로그래밍/CS 2024. 8. 6. 00:17

    운영체제 : CPU, 메모리, 디스크 할당 및 반환 등 각종 자원 관리

    커널 : 운영체제의 핵심부 (kernel.org 에서 리눅스 커널 소스코드 확인 가능)

    + 운영체제 중에서 커널이 아닌 것 : UI

    => 메모리에서 운영체제가 적재되는 공간 = 커널 영역

     

    모든 응용 프로그램은 자원에 임의 접근이 불가능 = 반드시 운영체제를 통해서만 가능

    => 운영체제는 일종의 문지기 역할을 수행함

     

    이중 모드

    • 커널 모드 : 운영체제 서비스를 제공 받을 수 있음 (입출력 가능) = 커널 영역의 코드 실행 가능
    • 사용자 모드 : 운영체제 서비스를 지공 받을 수 없음 (입출력 불가능) = 커널 영역의 코드 실행 불가능

    운영체제 서비스 : 프로세스 관리, 자원(CPU, 메모리, 디스크) 관리 접근 및 할당, 파일 시스템 관리

     

    시스템 콜 : 운영체제 서비스를 제공받기 위해 커널 모드로 전환하는 것

    - 응용 프로그램이 자원에 접근하기 위해 거치는 과정 => 인터럽트이기 때문에 응용프로그램 작업을 중단한 뒤, 운영체제의 코드 실행 후 작업 재개

     

    <LINUX 기반 관련 명령어>

    strace : 시스템 콜을 추적하기 위한 도구

    PID = Process ID => PID 활용해서 시스템 콜 트레이스 가능

    $ strace -p (PID)
    
    $ strace -t			# 타임스탬프
    $ strace -tt			# 밀리세컨드 타임스탬프
    $ strace -T			# 각 시스템 호출 소요 시간
    
    $ strace -c			# 시스템 호출 요약 결과 출력
    $ strace -e trace=		# 시스템 호출 결과 필터링
    
    
    $ touch 파일명			# 파일 생성
    $ rm 파일명			# 해당 파일 삭제

     

     

    대표적인 리눅스 시스템 콜

    # 파일(디렉토리, 소켓 등) 여는 시스템 콜, 파일 디스크립터 반환
    $ open
    
    # 파일 닫는 시스템 콜 = 파일 관련 자원 해제 역할
    $ close
    
    
    # 파일 디스크립터에서 데이터 읽어들이는 시스템 콜
    $ read
    
    # 파일 디스크립터에 데이터를 쓰는 시스템 콜
    $ write
    
    
    # 프로세스를 복제하여 자식 프로세스 생성 => 프로세스를 계층적으로 구성하고 관리함
    $ fork
    
    # 현재 프로세스의 주소 공간을 새로운 프로세스로 덮어 씀 => 자식 프로세스는 다른 코드 실행
    $ exec
    
    
    # PID 반환하는 시스템 콜
    $ getpid
    
    # 부모 프로세스의 PID를 반환하는 시스템 콜
    $ getppid
    
    
    # 시스템 로그 메시지 남기기
    $ syslog
    
    
    # 실행 중인 프로그램 종료
    $ exit

     

     

    프로세스 : 실행 중인 프로그램 => 같은 프로그램도 별도의 프로세스가 될 수 있음

    • 포그라운드 프로세스 : 사용자와 직접 상호작용 중인 프로세스
    • 백그라운드 프로세스 : 사용자와 상호작용 하고 있지 않은 프로세스
    $ systemctl list-units --type service		# 각 서비스 상태 및 설명 출력

     

     

    프로세스 제어 블록(PCB) : 동시 다발적으로 실행되는 프로세스들 관리를 위한 프로세스 식별 및 상태 확인용 데이터

    - 같은 프로그램이더라도 다른 프로세스로 실행 중이라면 PCB 값 다름 => 운영체제가 프로세스를 식별하는 기준

     

    PCB가 가지고 있는 값

    • PID(PPID)
    • 레지스터
    • 스케줄링 정보
    • 메모리 정보
    • 사용한 파일 정보
    • 입출력장치 정보

     

    문맥(context) : 실행을 재개하기 위해 기억해야할 정보

    문맥 교환 : 여러 프로세스들이 번갈아가면 실행될 때 이루어짐 = 프로세스 전환 시 CPU 내에 문맥이 교환되는 것

    => 할당 시간이 종료된 프로세스의 문맥을 저장하고, 실행될 프로세스의 문맥을 불러오는 것

    <<문맥 교환이 너무 빠르게 이루어지면 비용이 증가해 시스템이 느려질 수 있으니 적당한 속도로 이루어지는 것이 좋음>>

     

    프로세스 커널 영역에서는 PCB로 구성됨

    사용자 영역 구성 요소

    • 스택 영역 : 임시로 저장되는 영역 (매개 변수, 지역 변수 등)
    • 힙 영역 : 사용자(개발자)가 직접 할당 가능한 공간 - 메모리 영역 할당, 사용 완료 후에는 해제할 것 (직접 해제 or 자동 해제(가비지 컬렉션)) => 할당 미해제 시 메모리 누수 발생할 수 있음
    • 데이터 영역 : 프로그램이 실행되는 동안 유지할 데이터 (전역 변수 등)
      • BSS 영역 : 초기값이 없는 데이터는 여기에 저장, 초기값이 있는 데이터는 데이터 영역에 저장
    • 코드 영역 (텍스트 영역) : 실행 가능한 코드, 즉, 기계어로 이루어진 명령어 적재 (Read Only)

     

    동적 영역

    • 힙 영역 : 낮은 주소에서 높은 주소로 할당
    • 스택 영역 : 높은 주소에서 낮은 주소로 할당

    정적 영역

    • 데이터 영역
    • 코드 영역
    $ top		# 리소스 모니터링 시 활용되는 명령어

     

     

    대표적인 프로세스 상태

    • 생성 (new)
    • 준비 (ready) : 바로 실행 가능한 상태이지만 기다리고 있는 상태
    • 실행 (running)
    • 대기 (blocked) : 지금 바로 실행할 수 없는 상태
    • 종료 (terminated)

    리눅스 프로세스(태스크) 상태

    • R (Running) : 실행
    • S (Sleeping) : 대기
    • W (Waiting) : 준비
    • S (Stopped) : 종료
    • Z (Zombie) : 프로세스 종료 및 자원 반환 후에도 커널 영역에 프로세스가 남아있는 상태

    프로세스는 계층적 구조로 관리됨

    $ pstree		# 프로세스 계층적 구조 확인 명령어

     

    fork-exec : 프로세스 생성 시 세트로 실행되는 명령어 => 복사본 만들고(fork), 새로운 코드로 덮어쓰기(exec)

     

     

    스레드 : 프로세스를 구성하는 실행 흐름 단위

    한 프로세스에 여러 스레드 존재할 수 있음 = 멀티 스레드

    스레드는 각기 다른 스레드 ID, 프로그램 카운터, 레지스터, 스택 정보 가짐

    <리눅스에서는 프로세스와 스레드를 명시적으로 구분하지 않음>

     

    멀티프로세스 vs 멀티스레드 : 가장 주된 차이점은 자원 공유 여부

    • 프로세스 간에는 "기본적으로" 자원 공유되지 않음 => 메모리 소모 큼
      • 프로세스 간 통신(IPC)으로는 프로세스 간 자원 공유 가능
    • 스레드 간에는 프로세스 자원 공유됨 => 하나의 스레드에 문제 발생 시 프로세스 자체가 멈춤

     

     

    CPU 스케줄링 : 운영체제가 공정하고 합리적으로 자원을 배분하는 방법

    CPU 자원은 한정되어 있으므로 프로세스 별 우선순위에 따라 할당함

    $ ps -el		# 프로세스 우선 순위 확인 가능
    # PRI : 운영체제 기준 우선순위, NI : 사용자가 조정 가능한 우선순위

     

    일반적으로 I/O bound process가 CPU bound process 보다 우선순위 높음

    => I/O bound process 가 수행되는 시간이 CPU bound process 보다 오래 걸리기 때문

    CPU 사용 구간 : CPU burst

    입출력 장치 사용 구간 : I/O burst

     

    CPU 스케줄링 알고리즘 : 프로세스 우선순위를 토대로 CPU를 할당 받는 방법

     

    스케줄링 큐 : 한정적인 자원을 프로세스들의 요구사항에 따라 일목요연하게 관리하는 방법

    => 각 자원 별로 큐를 분리해서 줄을 세우는 것

    단, 큐라고 해서 무조건 FIFO로 구성될 필요는 없음

    • 준비 큐 : CPU 이용을 기다리는 프로세스들의 큐
    • 대기 큐 : 대기 상태 프로세스들의 큐, 입출력 종료 신호를 기다림 => 입출력 종료되면 준비 큐로 삽입됨

    큐라고 하더라도 우선순위에 따라 처리됨 => 우선순위 낮은 프로세스가 먼저 삽입되었어도 우선순위 높은 프로세스가 먼저 처리될 수 있음

     

    선점형 스케줄링 : 현재 실행 중인 프로세스 자원을 빼앗아 다른 급한 프로세스에 할당

    • 장점 : 프로세스에 자원 고루 할당 가능
    • 단점 : 문맥 교환 과정에서 오버헤드 많음

    비선점형 스케줄링 : 현재 실행 중인 프로세스 실행이 끝날 때까지 대기

    • 장점 : 문맥 교환 과정에서 오버헤드 적음
    • 단점 : 고르지 않은 자원 분배

     

    CPU 스케줄링 알고리즘

    • 선입 선처리 스케줄링(FIFO 스케줄링) : CPU를 먼저 요청한 프로세스부터 CPU를 할당하는 준비 큐에 삽입된 순서대로 실행되는 비선점형 스케줄링 => 부작용 : 호위 효과(convoy effect)
    • 최단 작업 우선 스케줄링(SJF 스케줄링) : 준비 큐 프로세스 중 CPU 이용 시간이 짧은 프로세스부터 실행함 => 호위효과 방지
    • 라운드 로빈 스케줄링(Round Robin(RR) 스케줄링) : 선입 선처리 스케줄링 + 타임 슬라이스 = 준비 큐에 삽입된 순서대로 실행하되, 타임 슬라이스만큼 실행하는 선점형 스케줄링
    • 최소 잔여 시간 우선 스케줄링(SRT 스케줄링) : 최단 작업 우선 스케줄링 + 라운드 로빈 스케줄링 = 작업 시간이 짧은 프로세스부터 처리하되, 타임 슬라이스만큼 실행함
    • 우선순위 스케줄링 : 프로세스마다 우선순위 부여 후 우선순위가 높은 순으로 스케줄링하는 범용적인 방법
      • SJF 스케줄링 : 작업시간 짧은 순으로 우선순위 부여
      • SRT 스케줄링 : 남은 시간 짧은 순으로 우선순위 부여
      • 문제점 : 아사(starvation) 현상
        • 모든 우선순위 스케줄링 알고리즘의 근본적인 문제
        • 우선순위 낮은 프로세스의 실행이 계속 연기되는 현상으로 우선순위 높은 프로세스 실행으로 인해 우선순위 낮은 프로세스들의 실행이 불가능한 것
        • 해결책 : 에이징(aging) - 대기시간이 길어지면 우선순위를 점차 높이는 방식
    • 다단계 큐 스케줄링 : 우선순위 별로 준비 큐를 여러 개 사용하는 스케줄링
      • 프로세스 유형별로 큐 구분 가능 - CPU 바운드, I/O 바운드, 백그라운드, 포그라운드, 실시간 프로세스 등
      • 큐 별로 다른 스케줄링 알고리즘 적용 가능
      • 큐 별로 다른 타임 슬라이스 적용 가능
      • 기본적으로 프로세스는 한번 삽입되면 큐 간에 이동이 불가능 => 아사 현상 발생
    • 다단계 피드백 큐 스케줄링 : 다단계 큐의 아사 현상 발생 가능성을 개선한 것
      • 프로세스가 큐 간에 "이동 가능"
      • 우선순위가 높더라도 정해진 타임 슬라이스 내에 끝나지 않으면 우선순위가 점점 낮아짐
      • 우선순위가 낮더라도 대기시간 길어질수록 우선순위 높아짐 = 에이징
      • 즉, CPU를 주로 사용해야하는 CPU 바운드 프로세스는 우선순위가 점점 낮아지고, 입출력 장치를 주로 사용해야하는 I/O 바운드 프로세스는 우선순위가 점점 높아짐

     

    리눅스 스케줄링 정책

    • 실시간 정책 스케줄링: 우선순위 높지만 데드라인 있음
      • SCHED_FIFO
      • SCHED_RR
    • 일반 정책 스케줄링 : 우선순위 낮음
      • SCHED_OTHER / SCHED_NORMAL
      • SCHED_BATCH
      • SCHED_IDLE

    CFS (Completely Fair Scheduler) : 비실시간 프로세스를 대상으로 하는 스케줄링 방식

     

    vruntime(virtual runtime) : 프로세스가 그 동안 실행한 시간을 정규화한 정보 

    vruntime 값이 작은 프로세스를 다음 실행할 프로세스로 삼음

    vruntime 별 태스크를 고르는 과정에서 RB tree 사용함

     

    타임 슬라이스 => nice 값에 비례해서 가중치를 할당하고 그 가중치 값을 바탕으로 타임 슬라이스를 할당함

     

    nice : 사용자 영역에서 설정한 프로세스 우선순위로 -20 ~ 19 범위 내에서 설정 가능

    nice 값이 커널 영역으로 넘어가는 순간 0 ~ 139 범위 내의 값으로 바뀜

    => 실시간 스케줄링되는 프로세스 : 0 ~ 99 / CFS 프로세스(비실시간) : 100 ~ 139

     

    # nice 명령어 : 새 프로세스 실행 시, 해당 프로세스에 우선순위 부여 (기본값 0)
    $ nice -n [우선순위] [program]
    
    # renice 명령어 : 이미 실행 중인 프로세스의 우선순위 변경
    $ renice [우선순위] [PID]

    '프로그래밍 > CS' 카테고리의 다른 글

    운영체제 (2)  (0) 2024.08.31
    컴퓨터 구조 (2)  (0) 2024.08.05
    컴퓨터 구조 (1)  (0) 2024.07.25
Designed by Tistory.