개발자로 후회없는 삶 살기
[OS] 프로세스와 스레드, 공유자원 관리 본문
서론
※ 아래 내용을 다룹니다.
- 프로세스
- 스레드
- 공유 자원과 경쟁상태
- 교착상태
https://github.com/SangBeom-Hahn/boost-interview
본론
- 프로세스의 상태
1. 생성 상태
프로세스를 생성한 상태로 fork와 exec 시스템 호출로 프로세스를 만든 상태이며, 이때 PCB가 만들어진다.
fork : 부모 프로세스의 주소 공간인 메모리의 (코드, 데이터, 힙, 스택) 상태를 그대로 복사하여 자식 프로세스를 생성하는 시스템 호출로 자식 프로세스의 초기 메모리 상태는 부모와 동일하지만, 프로세스는 독립적으로 동작하기에 이후 메모리 변경은 독립적으로 이루어진다.
exec : 프로세스를 최초에 생성하는 시스템 호출이다.
🚨 프로세스와 함수 강화
프로세스 : 프로그램을 메모리에 로드하여 인스턴스화한 프로그램 전체이며, 프로그램을 클래스, 프로세스를 객체로 보면 프로그램을 여러 개 더블 클릭 시 여러 개의 프로세스가 메모리에 로드된다. 메모리에 로드된 프로세스는 자신만의 주소 공간을 가지고, OS의 CPU 스케줄링에 의해 명령어를 해석하고 실행하며 이때 메모리에 로드된 코드와 시스템 자원을 사용하고 입출력이 동작한다.
함수 : 프로세스 내에서 호출되어지는 코드 블록, 프로세스의 주소 공간 내에서 실행됨
#include <stdio.h>
#include <unistd.h>
// 최대값을 찾는 함수
int find_max(int arr[], int n) {
// 최대값 찾는 로직
return max;
}
int main() {
int arr[] = {1, 3, 5, 7, 9};
int n = sizeof(arr) / sizeof(arr[0]);
pid_t pid = fork();
if (pid < 0) {
perror("fork failed");
return 1;
} else if (pid == 0) {
// 자식 프로세스
printf("자식 프로세스: 최대값 = %d\n", find_max(arr, n));
} else {
// 부모 프로세스
printf("부모 프로세스: 최대값 = %d\n", find_max(arr, n));
}
return 0;
}
위 코드를 보면, fork()로 부모와 자식 프로세스가 메모리에 로드되며, 이후 다르게 동작하여 각각 독립적으로 find_max 함수를 호출하여 상태가 달라질 수 있다. 프로세스는 프로그램의 인스턴스로 프로그램 전체를 의미한다. 즉, OS에서 실행 중인 프로그램의 독립적인 인스턴스로 메모리 공간을 가지며, CPU에서 실행된다.
1) 프로그램 로드 : OS에 의해 프로그램을 메모리에 로드하여 필요한 초기 데이터를 준비하여 프로세스를 생성함. 이때 코드, 데이터, 힙, 스택 등이 가상 메모리에 할당된다.
2) 프로세스 실행 : OS의 CPU 스케줄링에 의해 프로세스를 CPU에 할당하여 메모리에 로드된 코드와 시스템 자원을 사용하여 동작한다.
3) 함수 호출 : 프로세스가 실행될 때 프로세스 내의 코드에 작성된 함수를 메모리에서 읽어서 호출하고 실행한다.
4) 종료 : 프로세스가 끝나거나 종료 호출을 받을 경우 메모리를 반납한다.
프로세스를 일꾼으로 보면, 프로그램의 명령어를 순차적으로 실행하여 특정 작업을 수행하고 여러 함수를 호출하고 시스템 자원을 사용하여, 입출력을 수행하는 역할이다.
2. 그 외 상태 들
1) 대기 상태 : 메모리가 부족하여, CPU 스케줄러로부터 CPU 소유권을 받을 때가지 대기하는 상태로, 메모리 공간이 충분하면 메모리를 할당받음
2) 대기 중단 상태 : 메모리가 부족하여 CPU 소유권을 뺏기고 일시 중단된 상태
3) 실행 상태 : CPU와 메모리 소유권을 가지고 실행중인 상태
4) 중단 상태 : 프린터를 출력하면 잠시 멈추는 경우가 있다. 어떤 이벤트가 발생한 이후 기다리며 프로세스가 차단되어 멈춘 상태
5) 일시 중단 상태 : 대기 중단 상태와 비슷한 상태
6) 종료 상태 : CPU와 메모리 소유권을 모두 놓은 상태로 프로세스 KILL 등의 명령어로 종료 상태가 될 수 있음
- 프로세스의 메모리 구조
-> 동적 할당
런타임에 메모리를 할당하는 구조
1. 스택 : 지역, 매개 변수나 호출되는 함수를 할당하는 영역으로 호출될 때마다 환경과 관련 정보가 스택에 저장된다.
2. 힙 : MALLOC, FREE 등의 명령어로 동적으로 할당되며, VECTOR와 같은 자료 구조는 내부적으로 힙 영역에 저장한다.
-> 정적 할당
컴파일 타임에 메모리를 할당하는 구조
1. 데이터 : BSS(정적, 전역 변수, 상수, 0 혹은 아무것도 초기화 되지 않은 변수), DATA(0이 아닌 값으로 초기화된 변수), CODE(프로그램 코드) Segment가 할당된다.
클래스를 읽으면 static, 프로그램 코드 등이 데이터 영역에 생기고 객체가 생성될 때 힙을 차지하며, 객체의 함수 코드가 실행될 때 스택에 저장된다. 이를 CPU가 해석하고 레지스터에 로드하고 명령어를 수행한다.
- PCB(Process Control Block)
OS에서 프로세스의 메타 데이터를 저장하는 데이터로 EXEC나 FORK 발생 시 프로세스가 생성될 때 PCB가 저장된다. 프로그램을 더블 클릭하면 프로세스가 메모리에 올라가 생성되고 프로세스의 메타 데이터들이 PCB에 저장되어 관리된다.
-> PCB의 구조
프로세스 스케줄링 상태 : 중지, 대기, 실행 등 프로세스가 CPU 소유권을 부여받은 이후의 상태
PC : 프로세스에서 다음으로 호출될 명령어 번호로 프로세스가 로드되었을 때 실행되어야 할 명령어 라인을 명시
CPU 스케줄링 정보 : CPU 할당 시간 등 정보 저장
프로세스가 중단된 상태로 스왑 상태에 내려갈 때 PCB에 정보를 저장해야 한다.
-> 컨텍스트 스위칭
A 프로세스 실행 중에 B 프로세스 실행하는 경우 아래와 같이 저장과 로드가 일어난다.
A 프로세스 PCB 저장, B 프로세스 PCB 로드
PCB를 기반으로 프로세스의 상태를 임시 저장하고, 저장한 상태 그대로 다시 로드시키는 과정으로 인터럽트나 프로세스에 할당된 시간이 만료되면 발생한다. 컴퓨터는 여러 개의 프로세스가 동시에 병렬적으로 동작하는 것 같지만, 사실은 특정 시점에 실행되는 프로세스는 한개이며, 매우 빠른 속도로 컨텍스트 스위칭을 통해 교체되므로 동시에 처리되는 것처럼 인지하는 것이다. 이때 새로 로드된 프로세스의 캐시 데이터가 캐시클리닝으로 캐시미스가 발생한다.
- 멀티 프로세싱
하나의 프로그램을 여러 개의 프로세스로 수행하는 것으로 하나의 프로세스의 메모리나 프로세스에 문제가 발생해도 다른 프로세스를 이용할 수 있어 신뢰성이 높다.
-> 웹 브라우저의 멀티 프로세스 구조
브라우저 프로세스, 렌더러 프로세스, 플러그인 프로세스, GPU 프로세스
웹 브라우저 프로그램은 이렇게 여러 개의 프로세스가 각각 다른 작업을 수행하고 있다.
-> IPC(Inter Process Communication)
멀티 프로세스는 프로세스끼리 데이터를 주고 받고 공유 데이터를 관리할 수 있다. 클라이언트-서버간 통신이 대표적인 IPC이다. 이들은 모두 메모리를 완전히 공유하는 스레드보다 속도가 느리다.
1. 공유 메모리
원래 프로세스는 독립적으로 동작하여 A 프로세스의 메모리에 B 프로세스가 접근할 수 없지만, 공유 메모리는 프로세스 간에 동일한 메모리 블럭을 공유하여 통신한다. 공유 자원을 사용하기에 공유 메모리에 대한 동기화가 필요하며, 하드웨어 관점에서 CPU가 접근할 수 있는 공유 메모리는 램이다.
2. 그 외 IPC
1) 파일 : 디스크에 동일 파일에 여러 프로세스가 접근하여 통신한다.
2) 소켓 : 네트워크 간의 다른 컴퓨터로 네트워크 인터페이스를 이용하여 프로세스 간에 통신을 한다.
3) 익명 파이프 : 프로세스 간에 파이프 기반으로 통신하며 부모와 자식 간에는 가능하지만 다른 네트워크 상으론 불가하다.
4) 명명된 파이프 : 파이프 서버와 하나 이상의 파이프 클라이언트로 이루어져, 동시에 여러 파이프를 사용할 수 있고 컴퓨터 프로세스끼리 또는 다른 네트워크 상의 컴퓨터와도 통신할 수 있다.
5) 메시지 큐 : 공유 메모리를 사용했을 때 읽기, 쓰기 빈도가 높으면 구현과 동기화가 어려운데 이때 대안으로 메시지 큐를 사용하기도 한다.
- 스레드와 멀티스레드
-> 스레드
프로세스 내의 가장 작은 작업 단위로 프로세스는 여러 스레드를 가질 수 있다. 프로세스는 독립된 메모리 영역을 사용하지만, 스레드는 프로세스 내에서 자신만의 스택, 레지스터를 가지고 (힙, 데이터, 코드) 영역은 프로세스 내 스레드들끼리 공유한다.
프로세스 : 프로그램의 독립적인 실행 단위로, 각각의 프로세스는 별도의 가상 메모리를 가지고 프로세스 간에 기본적으로 메모리를 공유하지 않으며, 각 프로세스는 독립적으로 실행된다.
스레드 : 프로세스 내에서 실행되는 더 작은 실행 단위로, 실제 코드를 읽는 것은 스레드이다. 스레드는 같은 프로세스 내의 다른 스레드와 자원을 공유한다. 웹 서비스를 예로 들면, 하나의 요청이 들어오면 스레드가 요청의 흐름대로 코드를 읽고 응답하는 것이고 여러 요청이 오면 여러 스레드가 독립적으로 요청 흐름대로 동작하지만, 자원을 공유하여 동기화가 필요하다.
-> 멀티 스레드
프로세스 내 작업을 여러 스레드로 처리하는 기법으로 스레드끼리 자원을 공유하기 때문에 효율이 높다. 예를들어 웹 요청을 처리할 때 새 프로세스를 생성하는 대신 멀티 스레드를 사용하여 훨씬 적은 리소스를 소비하며, 한 스레드가 중단되어도 다른 스레드는 실행 상태일 수 있다.
크롬 프로그램 : 크롬 EXE 파일
크롬 멀티 프로세스 : 하나의 크롬 프로그램에서 여러 개의 프로세스가 각각 다른 일을 수행
크롬 멀티 스레딩 : 하나의 크롬 프로그램, 하나의 크롬 프로세스에서 여러 개의 스레드가 각각 다른 일을 수행
웹 브라우저의 렌더러 프로세스의 경우 여러 스레드가 다른 기능을 수행하고 있다. 프로그램, 멀티 프로세스, 멀티 스레드를 크롬으로 예를 들면 위와 같다.
- 공유 자원
여러 프로세스나 스레드가 공유하여 접근할 수 있는 자원이나 변수를 의미하며, 모니터, 프린터, 파일, 메모리 등이 있다. 자바 메모리의 메서드 영역의 static 변수를 생각할 수 있다.
-> 경쟁 상태(Race Condition)
여러 프로세스나 스레드가 동시에 공유 자원에 읽거나 쓸 때 타이밍이나 접근 순서에 따라 결과가 달라질 수 있는 상황을 의미한다. 경쟁 상태가 발생하면 프로그램이 공유 자원이 의도하지 않은 결과를 보일 수 있다.
1) 상호 배제 : 경쟁 조건을 막기 위해, 특정 프로세스나 스레드가 공유 자원을 사용하고 있다면 다른 스레드는 접근할 수 없도록 제어
2) 데드락 : 상호 배제를 유지하며 프로세스 간에 공유 자원을 요청하는 상태로, 상호 배제를 하면 데드락이 발생할 수 있다.
3) 기아상태 : 어떤 스레드가 영영 공유 자원을 획득하지 못하는 상태로, 자원 할당 정책이 공평하지 않거나, 낮은 스레드 우선 순위로 인해 발생할 수 있다. 이 경우, 공평한 자원할당 정책, 우선순위 동적 조정 등으로 해결할 수 있다.
경쟁 상태가 발생하면 위 3가지 제어 문제를 해결해야 하며, 공유 자원의 일관성을 유지하는 동기화가 필요하다.
-> 임계영역(Critical Section)
경쟁 상태를 일으키는 원인이 되는 코드 영역이다. 임계 영역에서 공유 자원에 접근할 수 있으며, 동기화하여 공유 자원의 일관성을 보장해야 한다. 대표적으로 전역 변수나 힙 메모리 영역을 들 수 있다.
1) 상호 배제 : 하나의 스레드가 공유 자원에 접근하면 다른 스레드는 접근할 수 없다.
2) 한정 대기 : 어떤 스레드도 영영 공유 자원에 접근할 수 없도록 하면 안된다.
3) 융통성 : 어떠한 스레드도 공유 자원을 이용하지 않은 상태에서는, 어떠한 스레드도 공유 자원을 사용할 수 있어야 한다.
임계 영역에서 경쟁 상태를 해결하는 방법에는 뮤텍스, 세마포어, 모니터가 있으며 3가지 모두 위 특성을 만족하며 락을 기반으로 동작한다.
- 동기화 방법
동기화란, 여러 스레드가 동시에 공유 자원에 접근할 수 없도록 순서를 제어하는 방법이다. 동기화를 하면 공유 자원의 일관성을 유지할 수 있다.
-> 락
공유 자원을 특정 스레드가 사용하고 있을 때, 다른 스레드는 접근할 수 없도록 제한하는 것. A가 접근하면 공유 자원에 락을 걸어 스레드 B가 접근하지 못하게 만들고 A의 작업이 종료되면 락을 풀고(언락) 대기(wait) 중이던 B가 작업을 수행한다.
-> 스핀락
스레드가 락을 획득할 때까지 무한 루프를 돌며 확인하는 동기화 매커니즘. 스레드가 실행되는 동안 공유 자원에 락을 걸고, 종료되면 락을 해제한다. 따라서 다음 스레드가 cpu를 차지하기 위해선 공유 자원에 락이 걸렸는지 확인하는 과정이 필요하다. 그냥 무작정 반복적으로 락이 반환될 때까지 확인하며 대기하는 것이다. 이 동기화 방법은 락을 획득할 때까지 반복해서 확인하므로 CPU를 계속 낭비하고 따라서 락이 준비되면 요청한 스레드를 깨우는 뮤텍스가 나왔다.
=> 뮤텍스
락을 기반으로 한 동기화 매커니즘으로 영역을 가진 스레드들의 Running time이 서로 겹치지 않게 각각 단독으로 실행되게 하는 락 기술이다. 한 스레드가 공유 자원을 이용하는 동안, 다른 스레드가 무작정 락을 획득할 수 있나 확인하는 것이 아니라, 대기 CPU에 들어가서 Sleep 상태로 기다리는 방식이다.
-> 순서
1) 스레드 a가 뮤텍스 락을 획득하고 임계 영역에서 공유 자원을 이용
2) 스레드 b가 뮤텍스 락을 획득할 수 있는 지 확인하고 없다면 대기 큐에서 Sleep
3) a가 자원 사용을 마치면 락을 반납
4) 락을 반납하면 대기 큐에서 대기하는 스레드에서 b를 찾아서 깨움
5) b가 뮤텍스 락을 획득하고 공유 자원을 이용
-> 특징
1) 락을 획득할 수 있는 지 계속 체크하느라 CPU를 소모하는 방식이 아니라, 대기 큐에 있는 동안은 자원을 내려놓고 Sleep 상태로 있는 Non-Busy-Wait 방식
2) 락을 획득할 수 있는지 Boolean으로 표시 (True : 획득 가능 / False : 획득 불가능)
3) Acquire/Release 메서드로 락을 획득하고 반납함 (Boolean이 False 이면 Acquire를 하지 못 하고 대기 큐에서 대기하다가 공유 자원을 이용하는 스레드가 Release를 하면 True가 되고 Acquire를 호출함
4) 락을 소유한 스레드만 접근 가능
-> 스핀락과 차이
1) 락을 가다리는 방식
스핀락 : 락을 획득할 수 있는지 다른 일을 하지 않고 CPU 자원을 사용하며 계속 확인하는 Busy-Wait 방식 (무한루프를 돌며 무작정 락을 얻으려고 시도한다. = 스피닝)
뮤텍스 : Boolean 값을 확인하고 대기 큐에서 대기하여 CPU 자원을 낭비하지 않는 Non-Busy-Wait 방식 (뮤텍스 락을 획득하지 못하면 자신의 이름을 써놓고 휴면 상태로 진입한다.)
2) 락을 해제할 때 동작 방식
스핀락 : 공유 자원을 사용하던 스레드가 락을 해제하면 밖에서 스피닝하던 스레드가 바로 스핀락을 획득
뮤텍스 : 공유 자원을 사용하던 스레드가 락을 해제하면 wait-list를 확인하고 대기하는 스레드를 찾아서 있다면 깨우고 락을 획득하여 임계 영역에 진입
=> 세마포어
정수값과 wait, signal을 사용하는 뮤텍스와 유사한 동기화 방법으로 최대 1개의 스레드만 공유 자원에 접근할 수 있는 뮤텍스와 달리 정수값은 공유 자원에 동시에 접근할 수 있는 최대 스레드의 개수를 나타낸다.
wait : 공유 자원을 사용하려는 스레드가 호출하는 메서드로 자신의 차례가 올 때까지 기다린다. 호출시 정수 값이 감소하며 자원을 사용할 수 있다면 공유 자원에 입장하고, 없다면 대기 큐에서 대기한다.
signal : 공유 자원을 사용하던 스레드가 사용을 끝내고 나올 때 호출하는 메서드로 다음 스레드로 순서를 넘겨준다. 호출시 정수값이 증가하고 공유 자원 사용을 끝냈다는 신호를 보낸다.
스레드가 공유 자원을 접근하면 세마포어가 wait을 해서 접근한 스레드가 자신의 차례가 올 때까지 기다리게 하고 공유 자원을 해제하면 세마포어가 signal로 다음 프로세스로 순서를 넘겨준다. 세마포어는 신호를 기반으로 하는 매커니즘이다.
1) 바이너리 세마포어
0과 1의 정수값을 가지며, 최대 1개의 스레드만 입장할 수 있는 세마포어
2) 카운팅 세마포어
최대 n개의 스레드가 입장할 수 있는 공유 자원을 관리하는 세마포어
값이 2 이상이면, 정수값 개수만큼의 스레드가 공유 자원에 접근할 수 있다. 스레드가 임계 영역에 진입하기 전에 값을 확인하고, 값이 허용된 범위 내에 있을 때만 락을 획득하는 형식으로 정수값이 -1이면 대기 큐에 1개의 스레드가 sleep 상태라는 것을 의미하는데 정수값이 음수이면 대기 큐에 대기중인 스레드의 개수를 나타낸다.
🚨 여러개의 스레드가 임계 영역에 들어가면 상호 배제 만족 못하는 거 아닌가?
정수 값이 2 이상이면 동시 접근 스레드 수가 2개 이상이라 경쟁 상태가 발생해야 하는 것 아닌가 싶은데, 세마포어만 구별해서 임계 영역의 개념을 좀 더 확장해서 이해해야 한다.
동기화 관점 임계영역 : 상호 배제를 지키기 위해 하나의 스레드만 접근 가능한 영역 (바이너리 세마포어에 해당)
세마포어를 고려한 임계 영역 : 하나 이상의 제한된 갯수의 스레드가 실행할 수 있는 영역 (카운팅 세마포어에 해당)
공중 화장실에 좌변기가 3개이면 3개까지는 동시에 사용할 수 있는 상황에서 정수값은 3이다. 공유 자원의 개수도 3이라서 3개의 스레드가 각각 하나씩 자원을 점유할 수 있어 경쟁 상태가 발생하지 않는다. 세마포어를 동기화 관점에서 보면 바이너리 세마포어만 고려하면 되고 위 예는 카운팅 세마포어라는 예외까지 고려한 좀 더 느슨한 확장 개념이다.
-> 뮤텍스와 공통, 차이점
1) 공통점 : 큐 대기 방식
락을 획득할 때까지 큐에서 CPU 자원을 내려 놓고 대기하는 Non-Busy-Wait 방식
2) 공통점 : 데드락 발생 가능성
데드락은 공유 자원에 동시에 여러 스레드가 접근했을 때 발생할 수 있으며, 뮤텍스와 세마포어는 공유 자원에 동시에 여러 스레드가 접근할 수 없도록 뮤텍스락, 정수갑, 큐를 사용하여 접근 순서를 제어하는 동기화 방법으로 데드락 발생 가능성이 낮다. 하지만 잘못 사용할 경우 데드락이 발생할 수 있다.
3) 차이점 : 락의 소유권
1) 뮤텍스 : 락을 획득한 스레드만이 락을 해제할 수 있다.
2) 세마포어 : 락 기반 매커니즘이 아니라, 단순히 사용 가능한 자원의 개수를 관리하는 정수값 기반 매커니즘으로 소유권 개념이 없고 누가 세마포어 값을 변경했는지 중요하지 않다. 스레드 a가 정수값을 감소시키고, b가 증가시킬 수 있다.
이 때문에 뮤텍스와 이진 세마포어는 최대 1개의 스레드만 접근 가능하더라고 비슷하지만 다르게 생각할 수 있다. 뮤텍스는 세마포어로 사용할 수 없고, 세마포어는 뮤텍스로서 사용할 수 있다.
4) 차이점 : 접근 가능한 스레드 개수
1) 뮤텍스 : 공유 자원에 한 개의 스레드 접근, boolean 락으로 관리
2) 세마포어 : 공유 자원에 N개의 스레드 접근, 정수값으로 관리
5) 차이점 : 작업 간 실행 순서 동기화
세마포어 : 시그널 매커니즘으로 순서를 제어할 때도 사용할 수 있다. 사진처럼 t1이 끝나고 3에 신호를 줘서 t3은 1이 끝나야만 2를 하도록 순서를 제어하는 순서 동기화를 할 때도 세마포어를 사용한다.
✅ 정리
1) 1개의 자원에 대한 상호 배제만 필요하다면 뮤텍스를 사용
2) 공유자원 접근 수를 조절하고, 실행 순서 동기화가 필요하면 세마포어를 사용
- 교착상태(데드락)
프로세스 A가 프로세스 B의 자원을 요청할 때 B도 A의 자원을 요청하는 상태로, 프로세스 간에 서로 점유하고 있는 자원을 요청하며 중단된 상태이다.
-> 원인
상호 배제 : 한 프로세스가 자원을 독점하고 있으면 다른 프로세스의 접근이 불가
점유 대기 : 특정 프로세스(A)가 자원을 점유한 상태에서, (A가) 다른 프로세스가 점유한 자원을 요청하는 상태
비선점 : 다른 프로세스의 자원을 강제로 가져올 수 없음
환형 대기 : 서로가 서로의 자원을 요청하며 기다림
위 4가지 조건을 모두 만족할 때, 데드락이 발생한다.
-> 해결 방안
1. 예방
4가지 조건을 모두 만족할 때 발생하는 것을 반대로 생각하여, 하나라도 발생하지 않도록 시스템을 설계하여 데드락 발생을 예방한다.
1) 상호 배제 부정
ex) 프린터는 동시에 다른 프린트를 할 수 없다.
동시에 여러 프로세스가 자원을 공유할 수 있도록 하는 방식이다. 하지만, 현실적으로 불가능하며 동기화 문제가 발생한다.
2) 비선점 부정
노란색 차가 추가적인 자원을 기다려야 한다면, 노란색 차의 자원을 파란색 차에게 양보할 수 있도록 한다. CPU 스위칭과 유사하다.
3) 점유대기 부정
작업 수행에 필요한 모든 자원을 획득할 수 있을 때만 자원을 할당하며 혹은, 할당된 자원이 아예 없을 때만 자원을 할당하도록 제약을 둔다.
1) 자원 2, 3을 할당할 수 있을 때만 파란색 차에게 할당
2) 자원 2를 가지고 작업을 수행하던 중 3이 필요하면 2를 반납하고 2, 3을 요청하도록 한다.
2번의 경우 3을 획득할 수 없는 경우 자원 2를 다른 프로세스에게 할당할 기회를 준다.
-> 단점
1) 자원 2, 3을 모두 할당했을 때 자원 2의 사용이 오래 걸린다면 자원 3의 효율이 떨어진다.
2) 인기가 많은 자원이라면 특정 프로세스는 자원을 획득할 수 없는 기아 문제가 발생할 수 있다.
4) 환형 대기 부정
리소스에 순서 체계를 부여하고 오름차순으로 자원을 할당하는 방식으로, 모든 프로세스들이 4번 자원을 할당한 상태에서 1번 자원을 할당하려면 처음부터 1번 자원을 할당하고 4번 자원을 할당하도록 해야한다. 이 방식으로 순환을 방지할 수 있고 가장 많이 사용되는 방식이다.
2. 회피
실행환경에서 추가적인 정보를 활용해서 데드락이 발생할 것 같은 상황을 회피한다. 데드락의 가능성이 없는 경우에만 자원을 할당한다.
예방이 시스템 레벨이라면, 회피는 실행 환경이다.
-> 은행원 알고리즘
프로세스의 자원 요청이 들어왔을 때, 데드락 발생 가능성이 발견되면, 데드락 발생 가능성이 없을 때까지 계속 자원 요청을 거절한다.
3. 검출 및 복구
데드락의 발생은 허용하되, 발생하면 복구한다.
1) 프로세스 종료
데드락이 발생하면, 프로세스를 하나씩 종료하며 데드락이 해결됐는지 확인한다. 극단적이지만, 현업해서 사용하는 경우가 있다.
2) 일시적 선점 허용
파란색 차가 자원 2를 사용하고 있더라도, 노란색 차가 자원 2가 필요하면 일시적으로 양보한다.
4. 무시
OS가 데드락 발생을 무시하고 개발자가 해결하도록 한다. 교착상태는 이를 처리하는 비용이 더 커서 아예 작업을 종료하는 방법을 현대 os가 많이 채택했다. 프로그램을 실행하다가 '응답없음'이라고 뜰 때 교착 상태가 발생한 것이다.
참고
'[개발자] > [CS]' 카테고리의 다른 글
[DB] 조인의 원리와 종류 (0) | 2024.07.03 |
---|---|
[DB] 정규화와 트랜잭션, 인덱스 (0) | 2024.06.18 |
[OS] 운영체제와 컴퓨터, 메모리 (0) | 2024.06.04 |
[네트워크] IP 주소, HTTP (0) | 2024.05.29 |
[네트워크] 용어, 네트워크 분류, TCP/IP 계층 (4) | 2024.05.22 |