From f771fdde8001e8d5eae6de1e8e679ae65a1e6937 Mon Sep 17 00:00:00 2001 From: hansoojeongsj Date: Sun, 18 Jan 2026 15:49:34 +0900 Subject: [PATCH] =?UTF-8?q?9=EC=A3=BC=EC=B0=A8=20=EC=9A=B4=EC=98=81?= =?UTF-8?q?=EC=B2=B4=EC=A0=9C=20=EB=8D=B0=EB=93=9C=EB=9D=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OS/Soojeong/Deadlock.md | 274 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 274 insertions(+) create mode 100644 OS/Soojeong/Deadlock.md diff --git a/OS/Soojeong/Deadlock.md b/OS/Soojeong/Deadlock.md new file mode 100644 index 0000000..c2f1ced --- /dev/null +++ b/OS/Soojeong/Deadlock.md @@ -0,0 +1,274 @@ +### 데드락 (Deadlock) + +데드락, 즉 `교착 상태`를 한마디로 정의하면 “이러지도 저러지도 못하는 꽉 막힌 상태"예요. 하지만 이를 제대로 이해하려면 먼저 우리 시스템에서 작업이 어떻게 돌아가는지 알아야 해요. 프로세스에 대해 정리한 지 시간이 많이 지나, 프로세스와 스레드에 대해 간단하게만 정리하고 넘어갈게요. + +### 프로세스와 스레드: 작업의 기본 단위 + +프로그램이 실행되는 기본 단위 두가지를 비교해볼게요. + +| **구분** | **프로세스 (Process)** | **스레드 (Thread)** | +| ------------- | ----------------------------------- | ------------------------------------- | +| **정의** | 실행 중인 프로그램의 독립적인 단위 | 프로세스 내부의 작업 흐름 | +| **자원 공유** | 독립된 메모리 영역 (공유 X) | Stack을 제외한 영역을 서로 공유 | +| **장점** | 하나가 죽어도 다른 쪽에 영향이 적음 | 응답 속도가 빠르고 효율적인 자원 사용 | +| **단점** | 컨텍스트 스위칭 비용이 높음 | 동기화 문제 및 데드락 위험 존재 | + + + + + +### 데드락은 동기화 도구를 잘못 써서 생기는 문제인가 ? + +``` +공유 자원 +-> 동시에 접근하면 위험 +-> 그래서 lock을 건다 (동기화) +-> lock이 꼬이면 데드락 +``` + +데드락을 알기 위해서는 이 흐름을 알아야 해요. + +1. 경쟁 상태 (Race Condition) + +- 여러 스레드가 같은 자원을 동시에 접근하는 상황 +- 실행 순서에 따라 매법 결과가 달라지는 불안정한 상태가 됨 + ⇒ 여러 스레드가 동시에 접근하지 못하게 막아야겠다 ! (lock의 필요성) + +1. 임계 구역 (Critical Section) + +- 공유 자원에 접근하는 위험한 코드 구간 +- 이 구간은 반드시 한 번에 하나의 스레드만 실행해야 함 + ⇒ 이 구역의 입구에 lock을 걸어두면 되겠다. + +1. 동기화 필요성 + +- lock을 걸면 속도가 느려지는데 꼭 필요한가 ? + ⇒ lock을 걸지 않으면 데이터가 깨짐 + ⇒ 느린 것보단 틀린 게 더 문제가 됨 + +1. Mutex vs Semaphore (lock을 거는 방법) + +- Mutex: 한 명만 가질 수 있는 열쇠, 열쇠를 가진 스레드만 임계 구역에 들어갈 수 있음 + ``` + a 스레드가 lock + -> a만 unlock 가능 + -> b가 대신 unlock 불가 + ``` +- Semaphore: 여러 명이 사용 가능한 번호표, 허용된 개수만큼 스레드가 들어갈 수 있음 + + ``` + 프린터 3대, 스레드 10개 + -> 최대 3명이 프린터 동시 사용 가능 + -> 누가 어떤 프린터 사용하는지는 중요하지 않음 + => semaphore = 3 + + 스레드가 프린터 사용하려고 할 때, + wait() + -> 남은 프린터 개수 1 감소 + -> 남은 프린터 개수가 0 보다 크면 바로 프린터 사용이 가능 + -> 남은 프린터 개수가 0이면 대기 + + 다 사용하고 나오면, + signal() + -> 남은 프린터 개수 1 증가 + -> 대기 중이던 스레드를 하나 깨움 + + ------ + signal을 누가 했는지 중요하지 않음 + -> Semaphore는 이 signal이 누가 들어가서 썼는지 추적하지 않음 + ``` + +- Mutex = 이 방은 지금 누가 쓰고 있나? +- Semaphore = 이 건물에 몇 명까지 들어올 수 있나? + +⇒ Mutex는 소유 개념이 있고, Semaphore는 소유 개념 없이 개수만 관리 + +``` +공유 자원이 존재 +-> 데이터 오염 방지를 위해 임계 구역 설정 +-> lock(mutex/semaphore)을 걸어 순서 제어 +-> 이 lock이 꼬여 서로가 서로를 기다리는 +-> 데드락 발생 +``` + +### 왜 lock이 꼬여 서로가 서로를 기다릴까 ? + +데드락은 아래 설명할 4가지 조건이 단 하나도 빠짐없이 동시에 성립할 때만 발생해요. 반대로 말하면, 이 중 하나라도 깨지면 데드락은 성립되지 않아요. + +1. 상호 배제 (Mutual Exclusion) + + 한 자원은 한 번에 하나의 프로세스(또는 스레드)만 사용할 수 있는 상태예요. 데이터가 꼬이는 걸 막기 위해 우리는 의도적으로 lock을 걸어 이런 상황을 만들었어요. + +2. 점유와 대기 (Hold and Wait) + + 프로세스가 이미 가진 자원은 놓지 않은 채, 다른 자원이 풀리기만을 기다리는 상태예요. + +3. 비선점 (No Preemption) + + 자원을 가진 프로세스로부터 강제로 자원을 빼앗을 수 없는 상태예요. 자원은 오직 자발적으로 반납할 때만 다시 사용가능해서, 다른 하나가 자원을 놓지 않으면 다른 쪽은 계속 기다릴 수 밖에 없어요. + +4. 순환 대기 (Circular Wait) + + 대기하는 프로세스들이 원 형태를 이루는 상태예요. + a는 b의 자원을 기다리고, + b는 c의 자원을 가디라고, + c는 a를 기다리게 되면 아무도 움직일 수 없는 데드락이 완성돼요. + - 자원 할당 그래프 (Resource Allocation Graph) + + 데드락을 설명할 때 순환 대기를 시각적으로 보여주는 도구로, + 프로세스는 원, 자원은 사각형으로 그려요. + + 화살표가 자원 -> 프로세스면 할당, + 프로세스 -> 자원이면 대기예요. + + 이 그래프에서 사이클이 발견되면 데드락이 발생했거나 발생할 가능성이 있다는 뜻이에요. + +### 어떻게 이 데드락 상태를 벗어날 수 있을까 ? + +데드락을 해결하는 방법도 크게 4가지로 나눌 수 있어요. + +1. 데드락 예방 (Prevention) + + 데드락 발생 조건 4가지 중 하나를 아예 발생하지 않도록 설계하는 방법이에요. + - 상호 배제 제거: 모든 자원을 공유하게 만드는 방식 (현실적으로 거의 불가능) + - 점유와 대기 제거: 자원이 필요한 경우, 한 번에 모든 자원을 요청하도록 강제함 + - 비선점 제거: 자원을 점유한 프로세스가 다른 자원을 기다릴 때, 현재 가진 자원을 강제 회수함 + - 순환 대기 제거: 자원에 순서를 매겨, 반드시 정해진 순서(낮은 번호 → 높은 번호)로만 요청하게 함 + + ⇒ 특징: 데드락은 확실히 막지만, 자원 활용도가 낮아지고 비효율적이라는 단점이 있어요. + +2. 데드락 회피 (Avoidance) + + 자원 할당 시 데드락 발생 가능성을 미리 계산하여 안전한 경우에만 자원을 할당하는 방법이에요. + - 은행원 알고리즘(Banker’s Algorithm): 자원을 할당했을 때 시스템이 '안전 상태(Safe State)'를 유지할 수 있는지 미리 검사해요. 안전하다면 할당, 아니면 대기해요. + + ⇒ 특징: 데드락을 유연하게 막을 수 있지만, 프로세스가 사용할 최대 자원량을 미리 알아야 한다는 제약이 있어요. + 실제 프로그램이 실행 중에 얼마나 많은 메모리나 자원을 쓸지 예측하는 것은 어려워서 잘 쓰이지 않아요. + +3. 데드락 탐지 및 회복 (Detection & Recovery) + + 데드락 발생을 허용하되, 시스템이 주기적으로 데드락 여부를 체크하여 발견 시 조치하는 방법이에요. + - 탐지: 자원 할당 그래프 등을 통해 현재 데드락이 발생했는지 감시 + - 회복: 데드락에 빠진 프로세스를 강제 종료하거나, 필요한 자원을 강제로 회수(선점)하여 해결 + + ⇒ 특징: 예방/회피보다 시스템 부담은 적지만, 작업이 중단되거나 데이터 손실 위험이 있어요. + +4. 데드락 무시 (Ostrich Algorithm) + + 데드락 처리 비용이 발생 확률보다 크다고 판단될 때 사용하는 현실적인 대처법이에요. + - 타조 알고리즘: 타조가 모래에 머리를 박듯 문제를 무시 + + ⇒ 현실: Windows, Linux 등 현대 운영체제는 데드락이 매우 드물게 발생하므로, 별도의 방지 로직을 두기보다 사용자가 직접 프로세스를 종료하게 함으로써 성능 이득을 챙기는 방법이에요. + +### 식사하는 철학자 + +데드락을 검색하면 대표적으로 나오는 고전 문제예요. + +> 5명의 철학자가 원탁에 앉아서 식사를 한다. 철학자들 사이에는 포크가 하나씩 놓여 있고, 철학자들은 다음의 과정을 통해 식사를 한다. +> +> 1. 일정 시간 생각을 한다. +> 2. 왼쪽 포크가 사용 가능해질 때까지 대기한다. 만약 사용 가능하다면 집어든다. +> 3. 오른쪽 포크가 사용 가능해질 때까지 대기한다. 만약 사용 가능하다면 집어든다. +> 4. 양쪽의 포크를 잡으면 일정 시간만큼 식사를 한다. +> 5. 오른쪽 포크를 내려놓는다. +> 6. 왼쪽 포크를 내려놓는다. +> 7. 다시 1번으로 돌아간다. + +이 문제는 앞에서 정리한 데드락 발생 조건 4가지를 모두 만족하는 상황을 그대로 보여주는 예제예요. + +1. 상호 배제 (Mutual Exclusion) + + 포크는 한 번에 한 철학자만 사용할 수 있어요. + + 즉, 포크는 **공유 자원이지만 동시에 사용될 수 없는 자원**이며, 이는 상호 배제 조건을 만족해요. + +2. 점유와 대기 (Hold and Wait) + + 각 철학자는 왼쪽 포크를 이미 집어든 상태에서, 오른쪽 포크가 사용 가능해질 때까지 기다려요. + + 자원을 하나 점유한 채, 다른 자원을 기다리는 상황이에요. + +3. 비선점 (No Preemption) + + 이미 다른 철학자가 집어든 포크를 강제로 빼앗을 수 있는 방법은 없어요. + + 포크는 오직 사용 중인 철학자가 내려놓아야만 다시 사용 가능해요. + +4. 순환 대기 (Circular Wait) + + 모든 철학자가 동시에 왼쪽 포크를 집는 순간, + + 각 철학자는 오른쪽 포크를 기다리게 된다. + + 이때, + - 철학자 A는 B의 포크를 기다리고 + - 철학자 B는 C의 포크를 기다리며 + - … + - 마지막 철학자는 다시 A의 포크를 기다리는 + + 원형 구조의 대기 관계가 형성되고, 결국 아무도 포크를 내려놓을 수 없는 데드락 상태가 돼요. + +--- + +정리 + +- 데드락 한마디로 + + 두 개 이상의 작업이 서로가 가진 자원을 기다리느라 둘 다 영원히 멈춰버린 상태를 말함 + 쉽게 비유하자면, 두 사람이 외나무다리에서 만났는데 서로 먼저 비키라고 요구하며 아무도 움직이지 못하는 상황 + +- 데드락 발생 조건 + + 4가지 조건이 동시에 만족되어야 함 + + 상호 배제(Mutual Exclusion): 자원은 한 번에 한 프로세스만 사용할 수 있음 + + 점유와 대기(Hold and Wait): 자원을 가진 상태에서 다른 자원을 기다림 + + 비선점(No Preemption): 다른 프로세스의 자원을 강제로 뺏을 수 없음 + + 환형 대기(Circular Wait): 프로세스들이 원 형태로 서로의 자원을 대기함 + +- 가장 현실적인 데드락 해결 법 + + 순환 대기 방지, + 모든 자원에 순서를 정해두고 무조건 정해진 순서대로만 자원을 요청하게 만들면 서로 꼬리를 물 일이 없어서 데드락이 원천적으로 예방됨 + +- 데드락이 발생하면 시스템은 어떻게 대처할지 + + 보통 두 가지 방법을 사용하는데, 데드락에 빠진 프로세스를 강제 종료하거나, + 한쪽 프로세스가 가진 자원을 강제로 선점해서 다른 쪽에게 몰아주는 방식으로 해결 + + 만약 중요도가 낮은 시스템이라면 그냥 무시하고 재부팅하기도 함 + +- 기아 상태, 데드락 차이 + + 데드락은 프로세스들이 서로 자원을 붙잡은 채 기다리면서 + 아무도 앞으로 진행하지 못하는 완전히 멈춘 상태 + + 기아 상태는 + 특정 프로세스의 우선순위가 낮아서 + 자원을 계속 못 받고 혼자만 계속 기다리는 불공평한 상태 + -> 이때 시스템 자체는 정상적으로 동작할 수 있음 + + 기아 상태는 오래 기다린 프로세스의 우선순위를 올려주는 + 에이징(Aging) 기법으로 해결 가능