CS study - 운영체제 - 2
프로세스와 스레드
프로세스(process) 는 컴퓨터에서 실행되고 있는 프로그램의 인스턴스를 말하며 CPU 스케줄링의 대상이 되는 작업(task), 데이터, 메모리등을 포함합니다. 각 프로세스는 운영체제로부터 독립적으로 실행되지만 운영체제로부터 자원을 할당받아 사용합니다.
스레드(thread) 는 프로세스 내 작업의 흐름, 실행되는 작은 실행 단위입니다. 하나의 프로세스는 여러개의 스레드를 가질 수 있으며, 각각 스레드는 프로세스 내에서 병렬적으로 실행됩니다. 스레드는 프로세스 내에서 같은 메모리 공간을 공유하므로 데이터와 자원을 공유합니다.
3-1 프로세스와 컴파일 과정
프로세스는 프로그램으로부터 인스턴스화된 것을 말합니다. 프로그램은 컴파일러가 컴파일 과정을 거쳐 컴퓨터가 이해할 수 있는 기계어로 번역되어 실행할 수 있는 코드로 변환하는 것을 의미합니다.
3-2 프로세스의 상태
- 생성 (create) : 프로세스가 생성된 상태를 의미합니다. 프로세스가 생성되면 운영체제는 프로세스를 초기화하고 메모리를 할당합니다.
- 대기 (ready) : 프로세스가 실행 준비가 된 상태를 말하며, 실행 가능한 상태로 CPU를 할당받을 수 있을 때를 의미합니다.
- 대기 중단 상태 (ready suspended) : 준비상태에서 일시적으로 멈춘 상태로, 이 상태에서는 메모리 부족등의 이유로 프로세스가 일시적으로 중단되었을 때 발생합니다.
- 실행 (Running) : 프로세스가 현재 실행중인 상태를 말하며 CPU를 할당받아 명령어를 실행하는 상태입니다.
- 중단 (Blocked) : 프로세스가 입출력 요청 등 다른 이벤트를 기다리는 상태를 말하며 프로세스가 입출력 작업등의 다른 이벤트를 기다리는 동안, CPU를 할당받지 못하고 대기하는 상태입니다.
- 일시 중단 (Blocked Suspended) : 블록 상태에서 일시적으로 멈춘 상태입니다. 이 상태는 메모리 부족등의 이유로 프로세스가 일시적 중단상태가 되었을 때 발생합니다.
- 종료 (Terminated) : 프로세스가 실행을 완료하거나, 강제 종료되었을 때를 말하며 프로세스가 운영체제에 의해 완전히 종료되었을 때 발생합니다.
3-3 프로세스의 메모리 구조
- 스택 (Stack) : 지역변수, 매개변수, 함수가 저장되고 컴파일 시 크기가 결정되며 동적인 특징을 갖으며 함수를 호출하면서 동적으로 크기가 늘어날 수 있는데, 이때 힙과 스택의 메모리 영익이 겹치면 안 되기 때문에 힙과 스택 사이의 공간을 비워둡니다.
- 힙 ( Heap ) : 동적으로 할당된 메모리가 저장되는 영역으로 런타임 시 크기가 결정됩니다.
- 데이터 (Data) : 전역변수, 정적변수가 저장되고, 정적인 특징을 갖는 프로그램이 종료되면 사라지면 변수가 들어 있는 영역으로 BSS 영역과 Data 영역으로 나뉘어져 있습니다.
- BSS (Block Started by Sysbol) 영역 : 초기화되지 않은 전역 변수와 정적 변수가 저장되는 메모리 영역입니다. 프로그램이 실행될 때 0으로 초기화 되며 일반적으로 프로그램의 크기를 줄이기 위해 0으로 초기화된 데이터를 저장하지 않는 경우에 사용됩니다.
- Data (Initialized Data) 영역 : 초기화된 전역 변수와 정적 변수, 상수등이 저장되는 메모리 영역으로, 프로그램이 실행될 때 초기값으로 초기화되며, 프로그램의 크기는 Data 영역의 크기에 영향을 받습니다.
- 코드 (Code) : 프로그램의 코드가 저장되는 메모리 영역으로 소스코드가 들어가는 영역입니다. 수정 불가능한 기계어로 저장되며 정적인 특징을 갖습니다.
3-4 PCB
Process Control Block는 운영체제에서 프로세스에 대한 메타데이터를 저장한 데이터를 말하며 프로세스 제어 블록이라고도 합니다.
PCB는 운영체제가 각 프로세스를 관리하기 위해 사용되며, 프로세스의 상태, 레지스터 값, 메모리 할당 정보, 입출력 장치의 상태 등 다양한 정보를 포함합니다.
- 프로세스 스케줄링 상태 : ‘준비’, ‘일시중단’ 등 프로세스가 CPU에 대한 소유권을 얻은 이후의 상태
- 프로세스 ID : 프로세스 ID, 해당 프로세스의 자식 ID
- 프로세스 권한 : 컴퓨터 자원 또는 I/O 디바이스에 대한 권한 정보
- 프로그램 카운터 : 프로세스에서 실행해야 할 다음 명령어의 주소에 대한 포인트
- CPU 레지스터 : 프로세스를 실행하기 위해 저장해야 할 레지스터에 대한 정보
- CPU 스케줄링 정보 : CPU 스케줄러에 의해 중단된 시간 등에 대한 정보
- 계정 정보 : 프로세스 실행에 사용된 CPU사용량, 실행한 유저의 정보
- IO 상태 정보 : 프로세스에 할당된 IO 디바이스 목록
컨텍스트 스위칭 Context Switching
PCB를 교환하는 과정, 프로세스에서 다른 프로세스로 교체하는 작업을 말합니다.
예를 들어, 컴퓨터는 많은 프로그램을 동시에 실행하는 것처럼 보이지만 현재 실행되고 있는 프로세스는 단 한개이며 많은 프로세스가 동시에 구동되는 것처럼 보이는 것은 다른 프로세스와의 컨텍스트 스위칭이 아주 빠른 속도로 실행되기 때문입니다.
- 인터럽트 발생 : 하드웨어 인터럽트나 소프트웨어 인터럽트가 발생했을 때 운영체제는 현재 실행 중인 프로세스를 일시적으로 중단하고, 인터럽트 처리를 위한 다른 프로세스를 실행합니다.
- 시간 할당량 만료 : CPU는 각 프로세스마다 일정 시간을 할당받아 실행되며, 이 시간이 만료되면 운영체제는 현재 실행 중인 프로세스를 일시 중단하고 다른 프로세스를 실행합니다.
- 멀티 태스킹 : 멀티 태스킹 환경에서는 여러개의 프로세스가 동시에 실행되며 이때 운영체제는 CPU를 각각의 프로세스에 일정 시간씩 할당하여 실행합니다. 이때 프로세스 간에 컨텍스트 스위칭이 발생합니다.
그외 특징
- 캐시미스 : 컨텍스트 스위칭이 일어날 때 프로세스가 가지고 있는 메모리 주소가 그대로 있으면 잘못된 주소로 변환이 되므로 캐시 클리어 과정을 겪게 되고, 이 떄문에 캐시미스가 발생합니다.
- 스레드의 컨텍스트 스위칭 : 스레드에서도 컨텍스트 스위칭이 일어나며, 스택 영역을 제외한 모든 메모리를 공유하기 때문에 스레드 컨텍스트 스위칭의 경우 비용이 적고 시간도 더 적게 걸립니다.
3-5 멀티프로세싱
여러개의 프로세스를 의미하며 멀티 프로세스를 통해 동시에 두가지 이상의 일을 수행할 수 있는것을 말합니다. 병렬로 처리가 가능하며 특정 프로세스의 메모리, 프로레스 중 일부에 문제가 발생해도 다른 프로세스를 이용해 처리가 가능하다는 장점이 있습니다.
웹 브라우저의 멀티 프로세스 구조
- 브라우저 프로세스 : 주소, 북마크, 뒤로가기, 앞으로가기 등 네트워크 요청이나 파일 접근 같은 권한을 담당합니다.
- 렌더러 프로세스 : 웹사이트 ‘보이는’ 부분의 모든 것을 제어합니다.
- 플러그인 프로세스 : 웹사이트에서 사용하는 플러그인을 제어합니다.
- GPU 프로세스 : GPU 를 이용해서 화면을 그리는 부분을 제어합니다.
IPC
멀티 프로세스는 IPC(Inter Process Communication)가 가능하며, IPC는 프로세스끼리 데이터를 주고받고 공유 데이터를 관리하는 매커니즘을 뜻합니다.
클라이언트와 서버를 예로 들 수 있는데, 클라이언트는 데이터를 요청하고, 서버는 클라이언트 요청에 응답하는 것도 IPC의 예로 들 수 있습니다.
종류로는 공유 메모리, 파일, 소켓, 익명 파이프, 명명 파이프, 메시지 큐가 있으며 메모리가 완전히 공유되는 스레드보다는 속도가 떨어집니다.
- 공유메모리 (shared memory) : 여러 프로세스에 동일한 메모리 블록에 대한 접근 권한이 부여되어 프로세스가 서로 통신할 수 있도록 공유 버퍼를 생성합니다.공유 메모리를 통해 여러 프로세스가 하나의 메모리를 공유할 수 있으며, IPC방식 중 어떤 매개체를 통해 데이터를 주고받는 것이 아닌 메모리 자체를 공유하기 때문에 불필요한 데이터 복사의 오버헤드가 발생하지 않아 가장 빠르며 메모리 영역을 여러 프로세스가 공유하기 때문에 동기화가 필요합니다.
- 파일 : 디스크에 저장된 데이터 또는 파일 서버에서 제공한 데이터를 말하며 이를 기반으로 프로세스간 통신을 합니다.
- 소켓 : 컴퓨터의 다른 프로세스나 네트워크의 다른 컴퓨터로 네트워크 인터페이스를 통해 전송하는 데이터를 의미하며 TCP와 UDP가 있습니다.
- 익명 파이프 : 프로세스간에 FIFO 방식으로 읽히는 임시 공간인 파이프를 기반으로 데이터를 주고받으며, 단방향 방식의 읽기 전용, 쓰기 전용 파이프를 만들어서 작동하는 방식을 말합니다.
- 명명 파이프 : 파이프 서버와 하나 이상의 파이프 클라이언트 간의 통신을 위한 명명된 단방향 또는 이중 파이프를 말하며, 클라이언트와 서버간 통신을 위한 별도 파이프를 제공하며 여러 파이프를 동시에 사용할 수 있습니다. 컴퓨터의 프로세스끼리와 다른 네트워크상의 컴퓨터와도 통신할 수 있습니다.
- 메시지 큐 (Message queue) : 메시지를 큐 데이터 구조 형태로 관리하는 것을 의미하며, 커널의 전역변수 형태 등 커널에서 전역적으로 관리되며 IPC방식에 비해 사용방버비 직관적이고 간단하여 다른 코드의 수정 없이 단지 몇줄의 코드만으로 간단하게 메시지 큐에 접근할 수 있는 장점이 있습니다.
3-6 스레드와 멀티스레딩
스레드는 프로세스의 실행 가능한 가장 작은 단위로 프로세스는 여러 스레드를 가질 수 있습니다.
코드, 데이터, 힙은 스레드끼리 서로 공유하며 그외에는 각자 생성합니다.
멀티스레딩은 프로세스 내 작업을 여러개의 스레드 즉, 멀티스레드로 처리하는 기법으로 스레드끼리 서로 자원을 공유하기 때문에 효율성이 높습니다. 하지만 한 스레드에 문제가 생기면 다른 스레드에도 영향을 끼쳐 스레드로 이루어진 프로세스에 영향을 줄 수 있다는 단점이 있습니다.
동시성 : 서로 독립적인 작업들을 작은 단위로 나누고 동시에 실행되는 것처럼 보여주는 것
3-7 공유 자원과 임계 영역
공유자원 Shared resource
시스템 안에서 각 프로세스, 스레드가 함께 접근할 수 있는 모니터, 프린터, 메모리, 파일, 데이터등의 자원이나 변수등을 의미하며, 이 공유 자원을 두개이상의 프로세스가 동시에 읽거나 쓰는 상황을 경쟁 상태(race condition)라고 합니다. 동시에 접근을 시도하면 타이밍이나 순서등이 결과에 영향을 줄 수 있는 상태입니다.
임계영역 Critical section
둘 이상의 프로세스, 스레드가 공유 자원에 접근할 때, 순서등의 이유로 결과가 달라지는 코드 영역을 말하며 이를 해결하기 위해 뮤텍스, 세마포어, 모니터등 세가지정도의 방법이 있으며 이 모두 상호배제, 한정 대기, 융통성이란 조건을 만족합니다. 이 토대가 되는 매커니즘은 잠금(lock)입니다.
- 상호배제 (Mutual Exclusion) : 한 프로세스가 임계영역에 들어갔을 때 다른 프로세스는 접근할 수 없도록 보호하는 것으로 임계영역에 대한 경쟁 상태를 방지할 수 있습니다.
- 한정대기 (Bounded Waiting) :특정 프로세스가 영원히 임계 영역에 들어가지 못하면 안된다. 이는 곧 프로세스나 스레드가 임계영역에 접근하기 위해서 대기하는 시간이 유한하다는 것을 보장함으로 특정 프로세스나 스레드가 임계영역에 대한 접근 권한을 얻지 못하는 상태가 무한히 지속되는 것을 방지합니다. 접근기회를 공정히 나누어야 합니다.
- 융툥성(Flexibilitiy) : 한 프로세스가 다른 프로세스의 일을 방해하면 안된다.
- 진행 (Progress) : 임계영역에 대한 접근 권한이 없는 프로세스나 스레드가 있을 때 접근 권한을 가진 프로세스나 스레드가 임계영역에 진입할 수 있도록 해야합니다.
- 데이터 무결성 (Data Integrity) : 임계영역에서 작업하는 동안 공유 자원의 무결성을 보장해야 합니다.
뮤텍스 Mutex
뮤텍스는 상호배제를 구현하여 한 번에 하나의 프로세스나 스레드만 임계영역에 접근할 수 있도록 하며 보통 이진 세마포어(Binary Semaphore)로 구현되며, 뮤텍스를 사용하는 프로세스나 스레드는 뮤텍스를 획득(Acquire)하고, 작업이 끝난 직후 반드시 뮤텍스를 반환(Release)해야 합니다.
- 상호배제 : 뮤텍스는 한번에 하나의 프로세스나 스레드만 접근할 수 있도록 보장합니다.
- 블로킹 (Block) : 뮤텍스를 획득하지 못한 프로세스나 스레드는 대기하며 뮤텍스가 반환될때까지 블로킹됩니다.
- 우선순위 역전(Priority Inversion) : 뮤텍스를 획득한 프로세스나 스레드가 다른 프로세스나 스레드의 작업을 방해할 수 있는 경우, 우선순위가 더 높은 다른 프로세스나 스레드가 뮤텍스를 획득하는 상황이 발생할 수 있으며 이를 우선순위 역전 문제라고 합니다.
- 재귀적사용 (Resursive Use) : 뮤텍스를 획득한 프로세스나 스레드는 다시 뮤텍스를 획득할 수 있습니다. 이를 재귀적 사용이라고 합니다.
세마포어 Semaphore
세마포어는 상호배제와 함께 프로세스나 스레드간의 동기화를 위한 도구중 하나로 세마포어는 정수형 변수로 구성되며, wait(P)와 signal(V)이라는 함수로 제공합니다.
- wait 연산 : 세마포어의 값을 1 감소시키고, 값이 0보다 작다면 해당 프로세스나 스레드를 대기 상태로 만듭니다. 이를 통해, 세마포어를 사용하는 임계영역에 한번에 하나의 프로세스나 스레드만 접근할 수 있도록 합니다.
- signal 연산 : 세마포어의 값을 1 증가시킵니다. 이를통해, 세마포어 대기열에서 대기중인 프로세스나 스레드 중 하나를 깨워, 세마포어를 획득하도록 합니다.
특징
- 상호배제 : 세마포어를 사용해 임계영역에 하나의 프로세스나 스레드만 접근할 수 있도록 보장합니다.
- 블로킹(Block) : wait 연산에서 세마포어 값이 0인 경우, 해당 프로세스나 스레드를 대기 상태로 만듭니다.
- 우선순위 역전(Priority Inversion) : 우선순위가 높은 프로세스나 스레드가 세마포어를 획득하기 위해 대기하고 있는 경우, 우선순위가 낮은 다른 프로세스나 스레드가 먼저 세마포어를 획득하는 상황이 발생할 수 있습니다. 이를 우선순위 역전 문제라고 합니다.
- 카운팅 세마포어(Counting Semaphore) : 여러개의 값을 가질 수 있는 세마포어로 세마포어 값이 1보다 큰 경우, 해당 프로세스나 스레드는 세마포어를 획득할 수 있습니다.
- 이진 세마포어(Binary Semaphore) : 세마포어 값이 0 또는 1인 경우, 해당 프로세스나 스레드는 세마포어를 획득할 수 있습니다. 구현의 유사성으로 인해 뮤텍스는 바이너리 세마포어라고 할 수 있지만, 엄밀히 뮤텍스는 **‘잠금 매커니즘’**이고, 세마포어는 신호를 기반으로 상호배제가 일어나는 **‘신호 매커니즘’**입니다.
모니터
상호배제와 조건변수를 함께 지원하는 동기화 매커니즘입니다. 모니터 내부에는 임계영역에 대한 접근을 단일 스레드로 제한하며, 조건변수를 통해 스레드간의 통신과 조정을 가능하게 합니다.
진입 절차(Entry protocol)과 이용법(Usage protocol)로 구성되며, 진입절차는 모니터 내부에 들어가기 전에 충족하는 제약조건을 정의하고, 이용법은 모니터 내부에서 상호배제와 조건변수 사용에 대한 규칙을 정의합니다.
Java 에서 모니터는 synchronized 키워드를 이용하여 구현되며, 메서드나 블록을 통해 모니터의 진입과 이용을 관리할 수 있습니다. 자바에서 synchronized 키워드의 모니터는 해당 객체에 대한 Lock을 얻는 것으로 다른 스레드가 해당 객체를 동시에 사용하지 못하도록 하며, wait() 과 notify() 메서드를 이용해 조건변수를 사용할 수 있습니다. wait() 은 조건이 충족될때까지 스레드를 대기시키며, notify()는 대기중인 스레드 중 하나를 깨워 조건이 충족됐음을 알리는 역할입니다.
3-8 교착상태 deadlock
두 개 이상의 프로세스들이 서로가 가진 자원을 기다리며 중단된 상태를 말합니다. 서로 대기하면서 상대방이 자원을 반납하지 않으면 대기하는 것을 멈출 수 없는 상황이 발생하는 것 입니다.
교착상태의 원인
- 상호배제 : 한 프로세스가 자원을 독점하여 다른 프로세스들의 접근이 불가능
- 점유대기 : 프로세스가 점유한 자원을 다른 프로세스도 요청하는 상태
- 비선점 : 다른 프로세스가 사용중인 자원을 강제로 가져올 수 없습니다.
- 순환(환형) 대기 : 두 개 이상의 프로세스나 스레드가 자원을 얻기위해 대기하는 상태
교착상태의 해결방법
- 자원을 할당할 때 애초에 조건이 성립되지 않도록 설계합니다.
- 교착 상태 가능성이 없을 때만 자원이 할당되며 프로세스당 요청할 자원들의 최대치를 통해 자원 할당 가능 여부를 파악하는 ‘은행원 알고리즘’ 을 사용합니다.
- 교착 상태가 발생하면 사이클이 있는지 찾아보고 이에 관련된 프로세스를 한개씩 지웁니다.
- 교착 상태는 매우 드물게 일어나기 때문에 이를 처리하는 비용이 더 커서 교착상태가 발생하면 사용자가 작업을 종료합니다.
은행원 알고리즘 : 총 자원의 양과 현재 할당한 자원의 양을 기준으로 안정 또는 불안정 상태로 나누고 안정 상태로 가도록 자원을 할당하는 알고리즘
CPU 스케줄링 알고리즘
CPU스케줄러는 해당 알고리즘에 따라 프로세스에서 해야 하는 일을 스레드 단위로 CPU에 할당합니다.
프로그램이 실행될 때 CPU 스케줄링 알고리즘이 어떤 프로그램에 CPU소유권을 줄것인지 결정하며 이 알고리즘은 CPU이용률은 높게, 주어진 시간에 많은 일을 하게, 준비 큐(ready queue)에 있는 프로세스는 적게, 응답 시간은 짧게 설정하는 것을 목표로 합니다.
4-1 비선점형 방식 non-preemptive
프로세스가 CPU를 할당받으면 다른 프로세스가 강제로 뺏을 수 없는 방식으로 스스로 소유권을 포기하기 때문에 컨텍스트 스위칭으로 인한 부하가 적습니다.
- FCFS (First Come, First Served) : 도착한 순서대로 처리하는 알고리즘으로 길게 수행되는 프로세스 때문에 준비 큐에서 오래 기다리는 현상(convoy effect)가 발생하는 단점이 있습니다.
- SJF (Shortest Job First) : 실행 시간이 가장 짧은 프로세스를 가장 먼저 실행하는 알고리즘으로 긴 시간을 가진 프로세스가 실행되지 않는 현상(starvation)이 일어나며, 평균 대기 시간이 가장 짧지만 실제로 실행 시간을 알 수 없기 때문에 과거 실행 시간을 추측해서 사용합니다.
- 우선순위 : 기존 SJF 스케줄링의 경우 긴 시간을 가진 프로세스가 실행되지 않는 현상이 있었으며 이를 우선순위를 높이는 방법(aging)을 통해 단점을 보완한 알고리즘 입니다.
4-2 선점형 방식 preemptive
현재 사용하는 프로세스를 알고리즘에 의해 강제 중단시키고 다른 프로세스에 CPU소유권을 할당하는 방식입니다.
- 라운드로빈 (Round Robin) : 각 프로세스에 일정한 시간 할당량을 주어진 순서대로 CPU를 할당하며, 해당 시간이 지나면 다음 프로세스에 CPU를 할당합니다. 만약 그 시간안에 끝나지 않으면 다시 준비큐의 뒤로가는 알고리즘입니다
- SRF (Shortest Remaining Time First) : 스케줄링 알고리즘은 선점형 우선순위 알고리즘으로 현재 실행중인 프로세스가 끝나기까지 남은 시간을 고려해 가장 짧은 시간이 걸리는 프로세스를 먼저 실행하는 방법입니다.
- 다단계 큐 (MultiLevel Queue) : 여러개의 큐를 사용하여 프로세스를 관리하는 방식으로 각 큐마다 우선순위가 다르고 이 우선순위가 높은 순서대로 프로세스가 실행되며 라운드 로빈이나 FCFS 등 다른 스케줄링 알고리즘을 적용가능합니다.
Priority Scheduling : 비선점형, 선점형 두 방식 모두에서 사용이 가능합니다.