프로세스와 스레드
프로세스
프로세스는 CPU에 의해 메인메모리 상에 프로그램이 로드된 것을 말한다.
운영체제로부터 주소공간, 파일, 메모리 등을 할당받으며 이것들을 총칭하여 프로세스라고 한다.
프로세스의 메모리공간은 크게 스택, 데이터, 힙 영역으로 나뉜다. 스택 영역은 함수의 매개변수, 복귀주소, 로컬 변수(지역 변수)와 같은 임시 자료가 저장되는 공간이다. 데이터 영역은 전역변수가 저장되는 영역이다. 코드 영역은 프로그램의 소스코드가 적재되는 공간이다. 힙 영역은 동적할당되는 데이터가 저장되는 공간이다. 프로세스의 메모리공간은 크게 정적영역과 동적영역으로 나눌 수 있는데, 프로그램 실행중에 크기가 동적으로 변하는 스택과 힙 영역이 동적영역이고, 그 크기가 일정한 데이터와 코드 영역이 정적 영역이다.
PCB (Process Control Block)
PCB는 특정 프로세스에 대한 중요한 정보를 저장하고 있는 운영체제의 자료구조이다. 프로그램이 메인 메모리에 할당되면, 해당 프로그램에 대한 PCB가 생성되어서 연결리스트 형태의 자료구조에 추가된다. PCB는 메인 메모리의 운영체제 영역에 존재한다. (메인메모리는 운영체제와 관련된 프로그램이 적재되는 운영체제 영역과, 사용자 프로그램이 적재되는 사용자 영역으로 나뉜다.) - 다시 간단하게 말하자면, 운영체제는 프로세스 관리를 위해 프로세스의 생성과 동시에 고유한 PCB를 생성한다. 프로세스는 CPU를 할당받아 작업을 처리하다가도 프로세스의 전환(Context Switching)이 발생하면 진행하던 작업(현재 CPU 레지스터 값들의 상태)을 저장하고 CPU를 반환해야하는데, 이때 작업의 진행 상황을 모두 PCB에 저장하게 된다. 그리고 다시 CPU를 할당받게 되면 PCB에 저장되어있던 내용을 불러와 이전에 종료됐던 시점부터 다시 작업을 수행한다.
PCB에 저장되는 정보
- 프로세스 식별자 (PID)
- 프로세스 상태 : new, ready, running, waiting(blocking), terminated)등의 상태
- 프로그램 카운터(PC) : 프로세스가 다음에 실행할 명령어의 주소
- CPU 레지스터
- CPU 스케줄링 정보 : 프로세스의 우선순위, 스케줄 큐에 대한 포인터 등
- 메모리 관리 정보 : 페이지 테이블 도는 세그먼트 테이블 등과 같은 정보 포함 (페이지 테이블은 프로세스마다 하나씩 할당)
- 입출력 상태 정보 : 프로세스에 할당된 입출력 장치들과 열린 파일 목록
운영체제 프로세스 스케줄링 부분 보충 요망
페이징과 세그멘테이션 보충 요망
스레드
프로세스 "내의" 실행단위. 한 프로세스 내에서 동작되는 여러 실행 흐름으로 프로세스 내의 주소 공간이나 자원을 공유. 스레드는 스레드ID, 프로그램 카운터(PC), 레지스터 셋(집합), 그리고 스택으로 구성
같은 프로세스에 속한 다른 스레드와 코드, 데이터, 힙 영역 그리고 열린 파일이나 신호와 같은 운영체제 자원을 공유. 하나의 프로세스를 다수의 실행단위로 구분하여 자원을 공유하고 자원의 생성과 관리의 중복성을 최소화하여 수행능력을 향상시키는 것을 멀티스레딩이라고함.
각각의 스레드는 독립적인 작업을 수행해야하므로 별도의 PC값과 스택을 할당받는다.
멀티 스레드
멀티 스레딩의 장점
멀티 프로세싱의 경우 중복되는 데이터 영역이 생긴다. 위에서 말했다시피 프로세스의 메모리 영역은 크게 실행중 변하지 않는 정적영역과, 변하는 동적영역을 나뉜다. 동적 영역은 별도로 할당해주어야할 필요가 있지만, 정적영역은 크기가 변하지 않기 때문에 공유하여서 사용하면 메모리 공간의 효율성을 높일 수 있다. 또한 스레드간 통신의 경우도 IPC와 같이 별도의 운영체제 자원을 이용할 필요없이 전역변수의 공간(데이터 영역) 혹은 Heap 영역을 이용하여 데이터를 주고 받을 수 있다. 그렇기 때문에 IPC에 비해 스레드간 통신이 더 간단하다.
심지어 스레드의 컨텍스트 스위칭은 프로세스의 컨텍스트 스위칭과 달리 캐시 메모리(CPU캐시를 말하는 듯?)를 비울 필요가 없기 때문에 더 빠르다. - 이부분 더 찾아보기
따라서 System의 throughput (처리량?)이 향상되고 자원 소모가 줄어들며 자연스럽게 프로그램의 응답 시간이 단축된다.
스레드는 공유하는 영역이 많기 때문에 컨텍스트 스위칭이 빠르다.
캐시는 CPU와 메인 메모리 사이에 위치하며, CPU에서 한번 읽어들인 메모리의 데이터를 저장하고 있다가, CPU가 다시 그 메모리에 저장된 데이터를 요구할 때, 메인 메모리를 통하지 않고 데이터를 전달해주는 용도이다.
프로세스의 컨텍스트 스위칭이 일어났을 경우, 공유하는 데이터가 없으므로 캐시가 지금껏 쌓아놓은 데이터들이 무너지고, 새로 캐시 정보를 쌓아야한다. 이것이 프로세스 컨텍스트 스위칭이 부담이 되는 요소이다.
반면 스레드라면 저장된 캐시 데이터는 스레드가 바뀌어도 공유하는 데이터가 있으므로 의미있다. 그러므로 컨텍스트 스위칭이 빠른 것이다.
참고: https://agh2o.tistory.com/12
멀티 스레드 장점 정리
- 응답성 향상 : 한 스레드가 입출력으로 인해 작업이 진행되지 않더라고 (blocking 상태더라도) 다른 스레드가 작업을 계속하여 사용자의 작업 요구에 빨리 응답할 수 있다.
- 자원 공유 : 한 프로세스 내에서 독립적인 스레드를 생성하면 프로세스가 가진 자원을 모두 스레드가 공유하게 되어 작업을 원활하게 진행할 수 있다.
- 효율성 향상 : 여러개의 프로세스를 생성하는 것과 달리, 멀티 스레딩은 불필요한 자원의 중복을 막음으로써 시스템 효율성 향상
멀티 스레딩 문제점
멀티 프로세스 기반의 프로그래밍의 경우 공유자원이 없기 때문에 동일한 자원에 동시에 접근하는 일이 없지만, 멀티 스레딩의 경우 공유자원의 경쟁조건 문제가 발생한다.
이러한 공유자원 문제점을 해결하기 위해 스레드 동기화 처리를 해주어야한다. 동기화를 통해 작업 처리의 순서를 컨트롤하고, 공유자원에 대한 접근을 컨트롤하는 것이다. 하지만, 이로인해 병목현상이 발생하여 성능이 저하될 가능성이 높다. 따라서 과도한 락으로 인한 병목현상을 줄여야한다.
문제점 정리
- 자원을 공유하기 때문에 하나의 스레드가 문제 생기면 전체 스레드에 영향
- 공유자원 경쟁조건 문제(스레드 동기화 문제)
사용자 스레드, 커널 스레드
- 커널 스레드 : 커널이 직접 생성하고 관리하는 스레드 (커널은 운영체제의 핵심 기능(함수) 모음)
- 사용자 스레드 : 라이브러리에 의해 구현된 일반적 스레드
사용자 스레드가 커널 스레드를 사용하려면 시스템호출을 통해 커널 기능을 이용해야함.
사용자 레벨에서 멀티 스레드를 구현한 것, 사용자 레벨에서 구현하는 것이기 때문에 관련 라이브러리를 사용. 라이브러리는 커널이 지원하는 동기화 같은 기능을 "대신" 구현. 그러므로 커널 입장에서 해당 스레드는 하나의 프로세스 처럼 보임.
사용자 스레드는 커널 입장에서는 일반 프로세스이지만, 커널(운영체제)이 하는 일을 라이브러리가 대신 처리하여 여러 개의 스레드로 동작. 따라서 사용자 프로세스 내에 여러 개의 스레드가 존재하지만 커널의 스레드 하나와 연결되기 때문에 1 to N 모델이라함.
정리(멀티스레드 vs 멀티프로세스)
멀티 스레드는 멀티 프로세스보다 적은 메모리 공간을 차지하고 문맥교환이 빠르다는 장점이 있지만, 오류로 인해 하나의 스레드가 종류되면 전체 스레드가 종료될 수 있다는 점과 동기화 문제를 안고있다.
반면 멀티 프로세스 방식은 하나의 프로세스가 죽더라도 나머지 프로세스에는 영향을 끼치지 않고 정상적으로 수행된다는 장점이 있다. 하지만 멀티 스레드보다 많은 메모리 공간과 CPU 시간을 차지한다는 단점이 존재한다.
스케줄러
프로세스를 스케줄링하기 위한 Queue에는 세 가지 종류 존재
- Job Queue : 현재 시스템 내에 있는 모든 프로세스의 집합
- Ready Queue : 현재 메모리 내에 있으면서 CPU를 잡아서 실행되기를 기다리는 프로세스의 집합
- Device Queue (Blocking Queue) : Device I/O 작업을 대기하고 있는 프로세스의 집합
각각의 Queue에 프로세스들을 넣고 빼주는 스케줄러에도 크게 세 가지 종류가 존재 (장기 Long term / 중기 Medium term - Swapper / 단기 Short term - CPU Scheduler)
CPU 스케줄러
스케줄링 대상은 Ready Queue에 있는 프로세스들
FCFS
특징
- 먼저 온 프로세스 먼저 서비스해주는 방식, 먼저 온 순서대로 처리
- 비선점형 스케줄링, 일단 CPU를 점유하면 프로세스가 작업을 완료할 때까지 CPU를 반환하지 않음. 할당되었던 CPU가 반환될 때만 스케줄링이 이루어짐.
문제점
- 소요시간이 긴 프로세스가 먼저 도달하여 효율성을 낮추는 현상 발생
SJF
특징
- 다른 프로세스가 먼저 도착했어도 CPU burst time이 짧은 프로세스에게 선할당
- 비선점형 스케줄링
문제점
- 기아현상
- 효율성을 추구하는 것이 가장 중요하지만 특정 프로세스가 지나치게 차별받으면 안됨. 이 스케줄링은 극단적으로 CPU 사용이 짧은 job을 선호함. 따라서 사용시간이 긴 프로세스는 거의 영원히 CPU를 할당받을수 없음
SRTF(Shortest Remaining Time First)
특징
- 새로운 프로세스가 도착할 때마다 스케줄링 일어남
- 선점형 스케줄링
- 현재 수행중인 프로세스의 남은 burst time보다 더 짧은 burst time을 가진 새로운 프로세스가 도착하면 CPU를 빼앗김
문제점
- 기아현상
- 새로운 프로세스가 도달할 때마다 스케줄링을 다시하기 때문에 CPU burst time(CPU 사용시간) <-> IO burst time(참고)을 측정할 수가 없다.
Priority Scheduling 우선순위 스케줄링
특징
- 우선순위가 가장 높은 프로세스에게 CPU를 할당하는 스케줄링. 우선순위는 정수로 표현하게 되고 작은 숫자가 높은 우선순위를 가짐
- 선점형 스케줄링 방식
- 더 높은 우선순위의 프로세스가 도착하면 실행중인 프로세스를 멈추고 CPU 선점
- 비선점형 스케줄링 방식
- 더 높은 우선순위 프로세스 도착하면 ReadyQueue의 Head에 넣음
문제점
- 기아현상
- 무기한 봉쇄(Indefinite Blocking)
- 실행준비는 되어있으나 (Ready 상태) CPU를 사용못하는 프로세스를 CPU가 무기한 대기하는 상태 -> 이게 기아현상 아님?
해결책
- aging
- 아무리 우선순위가 낮은 프로세스라도 오래 기다리면 우선순위를 높여준다.
Round Robin
특징
- 현대적인 CPU 스케줄링
- 각 프로세스는 동일한 크기의 할당시간(Time Quantum)을 가짐
- 할당 시간이 지나면 프로세스는 선점당하고 ready queue의 제일 뒤에 가서 다시 줄을 선다.
- RR은 CPU 사용시간이 랜덤한 프로세스들이 섞여있을 경우 효율적
- RR이 가능한 이유는 프로세스의 context를 save할 수 있기때문 (PCB에 저장)
장점
- Response Time이 빨라짐
- n개의 프로세스가 ready queue에 있고, 할당시간이 q(time quantum)인 경우 각 프로세스는 q 단위로 CPU 시간의 1/n을 얻는다. 즉, 어떤 프로세스도 (n-1)q time unit 이상 기다리지 않는다.
- 프로세스가 기다리는 시간이 CPU를 사용할 만큼 증가한다. 공정한 스케줄링이라고 할 수 있다.
주의점
- 설정한 time quantum이 너무 커지면 FCFS와 같아진다.
- time quantum이 너무작아지면 스케줄링 알고리즘의 목적에는 이상적이지만 잦은 context switching으로 overhead가 발생한다.
- 따라서 적절한 time quantum을 찾는 것이 중요하다.
동기와 비동기
동기를 맞춘다는 것은 서로 다른 두 작업의 시작을 같게 맞추거나(시작하는 시간을 같이 한다는 뜻), 시작과 끝이 같도록 맞추는 것을 의미한다. (즉 한 작업이 끝나고 다른 작업이 시작하도록 한다는 뜻)
즉 동기의 경우 어떠한 메소드를 수행하고, 그 결과값을 반환 받은 후에 다음 작업으로 진행한다.(현재 작업의 끝과 다음 작업의 시작을 맞춘다.) 비동기는 값의 반환과 상관없이 다음 작업으로 진행한다.
프로세스 동기화
Critical Section(임계영역)
동일한 자원에 동시 접근하는 작업 (공유자원 경쟁조건 문제) 을 실행하는 코드 영역을 Critical Section이라고 함
임계영역 문제
프로세스들이 Critical Section을 함께 사용할 수 있는 프로토콜을 설계하는 것
해결을 위한 기본 조건
- Mutual Exclusion 상호배제
- Progress 진행의 융통성 (한 프로세스가 다른 프로세스의 진행을 방해해서는 안된다)
- Bounded Waiting 한정된 대기
해결책
Lock
- 하드웨어 기반 해결책, 동시에 공유자원에 접근하는 것을 막기 위해 Critical Section에 진입하는 프로세스는 Lock을 획득하고 Critical Section을 빠져나올 때 Lock을 방출함으로써 동시에 접근이 되지 않도록 한다.
- 멀티 프로세싱 환경에서는 시간적인 효율적 측면에서 적용 불가
Semaphore
- 소프트웨어상에서 Critical Section문제를 해결하기 위한 동기화 도구
종류
OS는 Counting/Binary 세마포어를 구분
- 카운팅 세마포어
- 가용한 개수를 가진 자원에 대한 접근 제어용으로 사용되며, 세마포어는 그 가용한 자원의 개수로 초기화 된다. 자원을 사용하면 세마포어가 감소, 방출하면 세마포어가 증가한다.
- 이진 세마포어
- 뮤텍스라고도 부르며, 상호배제의 Mutual Exclusion의 머릿글자를 따서 만들어졌다. 이름 그대로 0과 1사이의 값만 가능하며, 다중 프로세스들 사이의 Critical Section 문제를 해결하기 위해 사용한다.
단점
- Busy Waiting
- spin lock이라고 불리는 세마포어 초기 버전에서 임계영역에 진입해야하는 프로세스는 진입 코드를 계속 반복 실행해야하며, CPU 시간을 낭비했다.
- 이를 Busy Waiting이라고 부르며 특수한 상황이 아니면 비효율적인다.
- 일반적으로는 세마포에에서 임계구역에 진입을 시도했지만 실패한 프로세스에 대해 block을 시킨 후, 임계구역에 자리가 날 때 다시 깨우는 방식을 사용한다. 이 경우 busy waiting으로 인한 시간 낭비 문제가 해결된다.
- Dead Lock 교착상태
- 세마포어가 ready queue를 가지고 있고, 둘 이상의 프로세스가 임계구역에 진입을 무한정 기다리고 있고, critical section에서 실행되는 프로세스는 진입 대기중인 프로세스가 실행되어야만 빠져나올 수 있는 상황을 지칭한다.
Monitor
- 고급 언어의 설계 구조물로서 개발자의 코드를 상호배제하게끔 만든 추상화된 데이터 형태
- 세마포어의 경우 개발자의 잘못된 사용으로 임계구역 보호가 이루어지지 않을 수 있음
- 임계구역에서 세마포어를 획득하지 않고 진입하는 경우
- 임계구역에서 세마포어를 획득한 후, 임계구역을 나올 때 세마포어를 해제하지 않는 경우
- 세마포어의 획득과 해제의 순서가 바뀐경우
- 모니터의 경우 이러한 실수를 방지하기 위해 공유자원 사용시 무조건 세마포어 획득을 강제한 것
- 공유자원을 내부적으로 숨기고, 공유자원에 접근 가능한 인터페이스만 제공함으로써 자원을 보호하고 프로세스간 동기화를 시킨다. (객체지향 언어의 캡슐화 추상화와 비슷)
- 정리하면, 모니터는 보호할 공유자원을 임계구역으로 숨기고, 임계구역에서 작업할 수 있는 인터페이스만 제공하여 자원을 보호
- 공유자원에 직접 접근하기 위한 키 획득과 자원 사용후 해제를 모두 처리 (세마포어는 직접 키 해제와 공유자원 접근 처리가 필요)