OS
- 컴퓨터 하드웨어와 컴퓨터 사용자 간의 인터페이스로 동작하는 시스템 소프트웨어
- 컴퓨터의 하드웨어, 소프트웨어 자원을 효율적으로 관리한다.
- 부팅 시 메모리에 적재되어 실행을 시작하고 컴퓨터 종료시 까지 실행된다.
- 커널 코드로 컴퓨터의 모든 자원에 대해 배타적 독점해서 사용할 수 있는 권한이 있다
Sync vs Async
Sync
- 요청을 하고 응답을 받아야 다음 흐름을 실행하는 방식으로 순차적으로 실행
- 설계가 간단하다는 장점이 있지만 결과가 주어질 때 까지 대기해야 함
Async
- 요청을 하고 응답을 받기 까지의 대기 시간 동안 또 다른 동작이 실행되는 방식으로 병렬적으로 실행
- 대기시간동안 다른 작업을 할 수 있으므로 자원을 효율적으로 사용할 수 있다는 장점
Blocking vs Non-Blocking
Blocking
- 함수가 다른 함수를 호출하면 처리되야 되는 작업 흐름의 제어권을 다른 함수에게 넘겨주는것
- 제어권을 받은 함수는 작업을 실행하고, 제어권을 넘겨준 함수는 제어권을 다시 받을 때 까지 실행을 멈춤
Non-Blocking
- 함수가 다른 함수를 호출해도 제어권을 자신이 갖고 있는 것
- 제어권을 계속 가지고 있기 때문에 다른 함수를 호출해도 자신의 코드를 계속 실행함
Process
메모리에 적재되어 CPU에 의해 실행중인 프로그램으로 실행 중에 필요한 자원을 할당 받는다
PCB(Process Control Block)
- 커널영역에 프로세스 테이블을 통해 프로세스 목록, 정보를 관리하는 자료구조
- 프로세스가 생성될 때 마다 고유의 PCB가 생성되고 완료되면 PCB도 제거됨
- 관리하는 정보
- 프로세스 번호(PID)
- 프로세스 상태
- 프로세스 컨텍스트
- 스케쥴링 정보 등..
Process의 5단계 상태
- new : 프로세스가 생성 된 직 후
- running : CPU가 프로세스를 점유하면서 실행되서 명령어가 실행되는 상태
- waiting : 자원을 사용하기 위해서 CPU가 다른 작업을 끝낼 때 까지 기다리는 상태
- ready : I/O에 대기하며 CPU가 점유되기 전의 상태를 의미
- terminated : 프로세스가 완료되거나 외부로 부터 강제 종료한 상태
IPC(프로세스 간 통신 방법)
- 공유 메모리
- 프로세스가 메모리 할당을 커널에 요청, 커널은 해당 프로세스에 공유 메모리 공간을 할당한다.
- 메모리 영역이 구축된 이후 어떤 프로세스 건 메모리 영역에 접근 가능하고, 이때 프로세스가 메모리 영역에 첨부되는 방식으로 작동한다
- 프로세스 간 Read, Write를 모두 필요로 할 때 사용한다
- 중개자 없이 바로 메모리에 접근 가능하고, IPC중 가장 빠르게 작동한다
- 파이프(pipe)
- 통신을 위한 메모리 공간을 생성하여 프로세스가 데이터를 주고 받는 방식
- 운영체제에서 제공하는 Pipe는 단방향 통신을 제공하기 때문에 양방향 통신을 하기 위해서는 파이프 2개를 활용해서 통신
- 소켓(socket)
- 동일한 호스트 운영체제에서 실행되는 프로세스 간 데이터를 교환하기 위한 데이터 통신 엔드포인트
- 네트워크 소켓통신을 통해 데이터를 공유
- 데이터 교환을 위해 pc에서 임의의 포트를 정하고 포트 간에 데이터를 주고받는 방식
Thread
프로세스 내에서 실행되는 흐름의 단위
Thread가 독립적인 stack memory 영역이 필요한 이유?
- 스택은 함수 호출 시 매개변수나 지역변수를 저장하기 위해 사용하는 메모리 공간
- 메모리 공간이 독립적이라는 건 독립적인 함수 호출이 가능하다는 것이다
- 스레드는 프로세스 내에서 독립적인 흐름을 가져야 하기 때문에 실행 흐름을 추가하기 위해 최소 조건으로 독립된 스택을 할당
멀티 Thread 동기화 기법
- mutex와 spinlock 둘 다 자원에 lock이 걸린 경우 lock을 소유하지 않은 스레드는 풀릴 때 까지 대기해야 하는 특성을 가짐
mutex(뮤텍스)
- 한 스레드만 임계영역에 진입시키고, lock 변수로 잠금상태를 관리하고 나머지 스레드는 큐에 대기시킨다
- 스레드가 임계영역 진입 시 lock이 잠겨 있으면 대기큐에서 대기시키고 context switching을 한다. lock이 풀리면 다시 context switching을 하기 때문에 실행시간이 짧은경우 비효율적이다.
spinlock(스핀락)
- 대기큐를 갖지 않고 자원에 lock이 걸려 있는 경우 lock이 열릴 때 까지 lock 변수 값을 검사한다.
- 스핀락을 검사하는 스레드는 타임 슬라이스를 소비한다. lock을 소유한 스레드가 실행 되어야 lock이 풀리기 때문에 단일 cpu/코어를 가진 OS에서는 비효율적이다
semaphore(세마포어)
- n개의 자원을 사용하려는 m개의 스레드의 원활한 관리를 제공해서 자원을 소유하지 못한 스레드는 대기하고, 자원 사용을 마친 스레드에게 알리는 동기화 방식
- counter 변수를 선언해 사용가능한 자원의 개수를 체크하고, 자원 요청 시 실행하는 함수와 반환시 실행하는 함수로 구성되어 있다
multi process vs multi thread
multi process
- 각 프로세스는 독립적으로 구성. 프로세스 마다 코드, 데이터, 힙, 스택 영역을 각각 갖는다
- IPC를 사용해 통신
- 각각의 프로세스가 데이터 영역을 별개로 갖고 있기 때문에 context switching 시 발생하는 비용이 크다
multi thread
- 각 스레드 끼리 code, data, heap 영역을 공유하고 stack 만 각각 할당된다
- 자원을 공유하므로 공유 변수를 선언하고 그 자원으로 데이터를 통신
- context switching 비용이 적다
multi process 대신 multi thread를 사용했을 때 이점
- 자원의 효율성 증가
- 프로세스 간의 context switching 시 RAM과 CPU 사이의 캐시 메모리에 대한 데이터까지 초기화 되서 오버헤드가 크기 때문에 프로세스를 생성하여 자원 할당 하는 system call이 줄어 자원을 효율적으로 관리할 수 있다
- 처리 비용 감소 및 응답 시간 단축
- 스레드는 stack 영역을 제외하고 모든 메모리를 공유하기 때문에 스레드 간의 통신비용이 적다.
- context switching 시 스레드는 stack 영역만 처리하기 때문에 프로세스 간의 전환속도 보다 스레드 간의 전환속도가 빠르다
race condition
- 멀티 thread 환경에서 여러 thread가 공유하는 변수에 동시에 접근해서 공유데이터의 일관적인 결과를 보장할 수 없는 상황
- 해결방안
- 뮤텍스 : 공유 자원에 접근할 수 있는 스레드를 1개로 제한하는 방법. 임계영역을 가진 스레드가 겹치지 않게 각각 단독으로 실행됨
- 세마포어 : 공유된 데이터를 여러 프로세스가 접근하는 것을 막는 방법. 리소스를 경쟁적으로 사용하는 스레드에서 행동을 조정하거나 동기화 함
사용자 레벨 스레드 vs 커널 수준 스레드
사용자 레벨 스레드
- 스레드 라이브러리 함수를 호출해 스레드를 생성
- 스레드 라이브러리가 TCB를 사용자 공간에 생성하고 소유
- 라이브러리에 의해 스케쥴링됨
- 스레드가 시스템 호출으로 중단되면 프로세스의 모든 사용자 레벨 스레드가 중단
커널 수준 스레드
- 시스템 호출을 통해 스레드를 생성
- 커널이 TCB를 커널 공간에 생성하고 소유함
- 커널에 의해 스케줄링 됨
- 하나의 커널 레벨 스레드가 system call 호출 중 중단되도 해당 스레드만 중단
Context Switching
- 멀티 프로세스 환경에서 하나의 프로세스를 실행하고 있는 상태에서 인터럽트 요청으로 프로세스가 실행되어야 할 때 기존 레지스터 값을 저장하고 CPU가 프로세스를 수행할 수 있도록 프로세스의 context를 교체하는 작업
- 인터럽트가 발생하는 경우
- 입출력 요청
- CPU 사용시간 만료
- 자식 프로세스 생성
- 인터럽트 처리를 기다릴 때
교착상태
둘 이상의 스레드가 서로 상대방의 작업이 끝나기 만을 기다리기에 결과적으로 아무것도 못하는 상태
발생 필요조건
- 상호배제 : 최소 하나 이상의 자원이 비공유모드로 점유되어야 함
- 점유대기 : 최소한 자원 하나를 점유한 채, 다른 스레드에 의해 점유된 자원을 추가로 얻기위해 대기
- 비선점 : 점유된 자원은 다른 스레드에 의해 선점될 수 없음
- 순환대기 : 스레드가 체인을 구성하여 자원을 상호적으로 요청하는 상태
해결방법
- 교착상태 예방 : 교착상태 발생 요건 중 하나라도 발생하지 않게 함
- 교착상태 회피 : 미리 수행 상태를 파악하여 자원이 할당될 경우를 가정해 교착상태가 발생하면 자원 할당을 중지
- 교착상태 탐지&복구 : 교착상태가 발생을 탐지하여 시스템에 문제가 발생하지 않도록 조치
- 교착상태 무시 : 교착상태가 발생하지 않는다 가정함
Scheduling Algorithms
선점형
- 강제적으로 CPU 할당을 반납 받는 것
- 컨텍스트 전환 전에 시스템 호출 처리를 완료하거나 I/O 요청을 blocking 함
FCFS
- 먼저 요청하는 프로세스, 스레드가 CPU를 먼저 할당받는 알고리즘
- 처리율이 낮아 대기시간이 길어질 수 있다는 단점이 있다
SJF(Shortest Job First)
- 가장 CPU 작업시간이 작은 프로세스 부터 먼저 수행하는 스케쥴링 기법
- 실행시간이 짧은 작업을 신속하게 실행 하므로 평균 대기시간이 다른 스케쥴링 기법보다 짧다
- 프로세스 시작 전 프로세스의 작업 시간을 파악하기 어렵기 때문에 프로세스의 작업시간을 예측하는 과정을 거쳐야 된다. 현실적으로 적용하기 어려운 알고리즘이다
비선점형
SRT
- 큐에 현재 실행중인 프로세스의 잔여 CPU 점유시간보다 더 짧은 프로세스가 도착하면 짧은 프로세스에 선점되는 알고리즘
RR(Round Robin)
- 정해진 시간 할당량이 지나면 다른 프로세스가 할당되는 알고리즘
- 평균 대기시간이 길다 라는 단점이 있다
Paging
- 외부 단편화 문제를 해결하기 위해 프로세스의 논리 주소 공간을 떨어진 공간에 배정할 수 있도록 지원하는 메모리 관리 기법
- 고정 크기로 분할 하기 때문에 구현이 편하고, 시스템에 따라 page의 크기를 다르게 설정할 수 있다
- 페이지 단위를 작게 하여 내부단편화 발생 문제를 해결할 수 있지만, 매핑 과정이 복잡해 지기 때문에 비효율적이다
커널
- OS의 핵심 기능을 실행하는 코드와 데이터, 부팅 후 메모리에 상주하는 영역
- 커널 코드는 운영체제에서 제공하는 함수들의 집합으로 구성
- 어플리케이션에서 커널코드를 이용하기 위해 시스템 콜을 사용
- 어플리케이션이 컴퓨터 자원에 접근하면 충돌 혹은 훼손이 발생할 가능성이 있기 때문에 자원에 대한 접근 권한은 커널에만 부여
- 커널코드를 실행하기 위해 CPU 실행 모드를 커널 모드로 접근해야함
메모리 관리 기법
메모리 풀
- 필요한 메모리 공간을 필요한 만큼 사용자가 직접 지정하여 미리 할당받아 놓고, 필요할 때 마다 사용하고 반납하는 기법
- 메모리 할당, 해제가 잦은 경우 메모리풀을 쓰면 효과적이고, 미리 공간을 할당해놓고 쓰기 때문에 할당과 해제로 인한 외부 단편화가 발생하지 않는다.
- 필요한 크기 만큼 할당 하기 때문에 내부 단편화 또한 생기지 않는다.
- 사용하지 않는 순간에도 할당해 놓으므로 메모리 누수가 있는 방식이다.
단편화
외부 단편화
- 남아있는 메모리 공간이 요청한 메모리 공간보다 크지만 남아있는 공간이 연속적인 홀이 아니여서 발생
- 메모리 압축 기법으로 해결 가능
- 메모리 압축 기법
- 주기억 장치 내 분산되어 있는 단편화된 공간을 통합해 하나의 커다란 빈 공간을 만드는 작업
- 주소 재할당이 동적인 경우만 가능하며 압축을 진행하는 시간으로 시스템 성능이 저하될 수 있음
내부 단편화
- 할당된 메모리가 요구한 메모리보다 더 커서 프로세스에 할당된 메모리 내부에 사용할 수 없는 홀이 생기는 현상
- 파티션의 크기를 줄이면서 완화될 수 있지만, 메모리 관리의 효율성은 떨어진다
세그먼테이션
- 프로세스를 연관된 정보들의 집합으로 나눠서 메모리에 배치하는 기법으로 외부단편화가 발생할 수 있다
- 구현
- 프로세스를 세그먼트의 집합으로 만들고, 내부적으로 code, data, heap, stack 세그먼트로 나눈다
- 세그먼트를 메모리에 할당할 때 세그먼트 테이블을 활용하는데, 세그먼트 크기(limit)와 세그먼트 시작 물리주소(base)로 구성되어 있다
- 주소변환
- 세그먼트에서 주소변환을 하는 경우 세그먼트 테이블을 통해 논리주소를 물리주소로 변환
- 세그먼트의 크기를 넘어서는 주소가 들어오는 경우 해당 프로세스를 강제로 종료
가상메모리
- 프로세스를 메모리와 보조저장장치에 나눠서 저장해 무한의 가상적인 메모리 공간을 두는 메모리 관리 기법
- 최소한의 부분의 프로세스만을 메모리에 할당하고 가용 메모리 부족 시 일부 내용을 하드디스크의 스왑영역으로 옮겨 빈 영역을 확보
- 실제 설치되는 물리메모리보다 큰 크기의 프로세스가 실행될 수 없다는 단점이 있었기 때문에 가상메모리는 프로세스의 크기가 물리적 메모리의 크기에 제약을 받지 않는다는 장점이 있음
swapping
- 메모리가 부족할 때 실행에 필요하지 않는 부분은 보조저장장치로 이동하고, 필요할 때만 물리메모리로 이동하는 것
page fault
- 메모리에 모든 프로세스가 적재되지 않은 상황에서 메모리에 없는 page가 참조할 때 페이징 하드웨어가 os에게 비연속적으로 보내는 신호
페이지 교체 알고리즘
FIFO
- 가장 오래된 page frame을 먼저 교체하는 알고리즘
- 각 frame은 메모리에 적재되는 순서에 따라 순번이 매겨진다
- FIFO 큐를 이용
- 프레임을 더 많이 사용하는데 페이지 fault 횟수가 증가하는 이상현상이 발생할 수 있음
Optimal Page
- 최적 페이지 교체 알고리즘으로 앞으로 가장 오랫동안 사용되지 않을 page frame을 교체한다
- 향후의 프로그램이 어떻게 수행될 지 예측이 불가능하기 때문에 비현실적
LRU
- 최근에 적게 사용한 page frame을 앞으로도 미사용할 page로 간주하고 최근에 적게 사용된 page frame을 교체하는 알고리즘
- 각 page frame 마다 마지막 사용시간을 유지한다
- 모순현상이 나타나지 않기 때문에 일반적으로 좋은 성능을 띈다
LFU
- 참조 횟수가 가장 적은 페이지를 교체하는 알고리즘
- 교체 대상이 여러개라면 가장 오랫동안 사용하지 않은 페이지를 교체
MFU
- 참조횟수가 가장 많은 페이지를 교체하는 알고리즘