[Operating System Concepts 10th] 8. Deadlocks 리뷰
본 글은 Operating System Concepts 10th (운영체제) 책을 보며 내용을 개인 공부에 목적으로 정리했습니다.
이전에 운영체제 관련 강의들을 들으면서 정리한 시리즈 글들이 있는데,
지식을 습득하는 데 있어 가장 느리지만 가장 빠른 방법이 원본책을 자세히 보는 것이라 생각됩니다.
책 내용들을 최대한 이해하기 위해 거의 모든 내용을 담고 있습니다.
책 pdf 링크 : Operating System Concepts 10th Edition by Abraham Silberschatz Peter B Galvin Greg Gagne pdf free download
연습 문제 정답지 : Solutions of Practice Exercises, Tenth Edition of Operating System Concepts, AVI SILBERSCHATZ
8. Deadlocks
- 멀티 프로그래밍 환경에서는 여러 스레드가 한정된 자원을 사용하려고 서로 경쟁할 수 있다.
- 한 스레드가 자원을 요청했을 때, 그 시각에 그 자원을 사용할 수 없는 상황이 발생할 수 있고, 그때는 스레드가 대기 상태로 들어간다.
- 이처럼 대기 중인 스레드들이 결코 다시는 그 상태를 변경시킬 수 없으면 이런 상황을 교착 상태(deadlock)이라 한다.
- 목표
- Mutex 락을 사용할 때 어떻게 교착 상태가 발생할 수 있는지 보여준다.
- 교착 상태를 특징 짓는 4가지 필수 조건을 정의한다.
- 자원 할당 그래프에서 교착 상태 상황을 식별한다.
- 교착 상태 예방을 위한 4가지 방법을 평가한다.
- 교착 상태 회피를 위해 은행의 알고리즘을 적용한다.
- 교착 상태 감지 알고리즘을 적용한다.
- 교착 상태에서 복구하기 위한 접근법을 평가한다.
8.1 System Model
- 시스템(system)은 경쟁하는 스레드들 사이에 분배되어야 할 유한한 수의 자원들로 구성된다.
- 이들 자원은 다수의 유형으로 분할되며, 이들 각각은 동등한 다수의 인스턴스들로 구성된다.
- 만일 한 스레드가 어떤 자원 유형의 한 인스턴스를 요청하면, 동일 유형 자원의 임의의 인스턴스를 할당함으로써 요청이 충족된다.
- 스레드는 자원을 사용하기 전에 반드시 요청해야 하고, 사용 후에는 반드시 방출해야 한다.
- 스레드는 지정된 태스크(task)를 수행하기 위해 필요한 만큼의 자원을 요청할 수 있다.
-
정상적인 작동 모드하에서, 프로세스는 다음 순서로만 자원을 사용할 수 있다.
- 요청(Request) : 스레드는 자원을 요청한다. 요청이 즉시 허용되지 않으면(예를 들어 mutex 락을 다른 스레드가 가지고 있는 경우), 요청 스레드는 자원을 얻을 때까지 대기해야 한다.
- 사용(Use) : 스레드는 자원에 대해 작업을 수행할 수 있다.(예를 들어, 자원이 mutex 락이라면, 스레드는 임계구역에 접근할 수 있다.)
- 방출(Release) : 스레드가 자원을 방출한다.
- 스레드가 커널이 관리하는 자원을 사용할 때마다 매번 운영체제는 스레드가 자원을 요청했는지와 그 자원을 할당받았는지를 확인한다.
- 시스템 테이블이 각 자원이 가용 상태인지 또는 할당되었는지 기록하며, 각 할당된 자원에 대해서는 어느 스레드에 할당되었는지도 기록한다.
- 어떤 스레드가 현재 다른 스레드에 할당된 자원을 요청하면, 그 자원을 기다리는 스레드 큐에 입력될 수 있다.
- 한 스레드 집합 내의 모든 스레드가 그 집합 내의 다른 스레드에 의해서만 발생될 수 있는 이벤트를 기다린다면, 그 스레드 집합은 교착 상태에 있다.
8.2 Deadlock in Multithreaded Applications
- 먼저 POSIX mutex 락을 사용하여 멀티 스레드 Pthread 프로그램에서 어떻게 교착 상태가 발생할 수 있는지 살펴본다.
pthread_mutex_init()
: 가용한 mutex를 초기화한다.- Mutex 락은 각각
pthread_mutex_lock()
과pthread_mutex_unlock()
함수를 이용하여 획득되고 방출한다. - 한 스레드가 잠긴 mutex 락을 획득하려고 시도하면,
pthread_mutex_lock()
함수 호출은 mutex 락의 소유주가pthread_mutex_unlock()
함수를 호출할 때까지 이 스레드를 블록한다.
pthread_mutex_t first_mutex; // 생성
pthread_mutex_t second_mutex; // 생성
pthread_mutex_init(&first_mutex,NULL); // 초기화
pthread_mutex_init(&second_mutex,NULL); // 초기화
/* thread_one은 이 함수를 실행한다. */
void *do_work_one(void *param)
{
pthread_mutex_lock(&first_mutex);
pthread_mutex_lock(&second_mutex);
/*
Do some work
*/
pthread_mutex_unlock(&second_mutex);
pthread_mutex_unlock(&first_mutex);
pthread_exit(0);
}
/* thread_two는 이 함수를 실행한다. */
void *do_work_two(void *param)
{
pthread_mutex_lock(&second_mutex);
pthread_mutex_lock(&first_mutex);
/*
Do some work
*/
pthread_mutex_unlock(&first_mutex);
pthread_mutex_unlock(&second_mutex);
pthread_exit(0);
}
- thread_one이 first_mutex를 획득하고 thread_two가 second_mutex를 획득하게 되면 교착 상태가 가능하다.
- 하지만, 교착 상태가 가능하더라도 thread_two가 락을 획득하려고 시도하기 전에 thread_one이 first_mutex와 second_mutex를 획득하고 방출할 수 있다면 교착 상태는 발생하지 않는다.
8.2.1 Livelock
- 라이브락(livelock)은 또 다른 형태의 라이브니스 장애이다.
- 교착 상태가 어떤 스레드 집합의 모든 스레드가 같은 집합에 속한 다른 스레드에 의해서만 발생할 수 있는 이벤트를 기다리면서 블록되면 발생하는 반면에, 라이브락은 스레드가 실패한 행동을 계속해서 시도할 때 발생한다.
- 라이브락은
Pthreads pthread_mutex_trylock()
함수로 설명할 수 있다.- 이 함수는 블록되지 않고 mutex 락을 획득하려고 시도한다.
/* thread_one은 이 함수를 실행한다. */
void *do_work_one(void *param)
{
int done = 0;
while (!done) {
pthread_mutex_lock(&first_mutex);
if (pthread_mutex_trylock(&second_mutex)) {
/*
Do some work
*/
pthread_mutex_unlock(&second_mutex);
pthread_mutex_unlock(&first_mutex);
done = 1;
}
else
pthread_mutex_unlock(&first_mutex);
}
pthread_exit(0);
}
/* thread_two는 이 함수를 실행한다. */
void *do_work_two(void *param)
{
int done = 0;
while (!done) {
pthread_mutex_lock(&second_mutex);
if (pthread_mutex_trylock(&first_mutex)) {
/*
Do some work
*/
pthread_mutex_unlock(&first_mutex);
pthread_mutex_unlock(&second_mutex);
done = 1;
}
else
pthread_mutex_unlock(&second_mutex);
}
pthread_exit(0);
}
- 라이브락은 일반적으로 스레드가 실패한 작업을 동시에 재시도할 때 발생한다.
- 따라서 일반적으로 각 스레드가 실패한 행동을 재시도하는 시간을 무작위로 정하면 회피할 수 있다.
- 라이브락은 교착 상태만큼 흔히 일어나지는 않지만 동시 애플리케이션을 설계하는 데 있어 어려운 문제이며 교착 상태와 같이 특정 스케줄링 상황에서만 발생할 수 있다.
8.3 Deadlock Characterization
8.3.1 Necessary Conditions
- 교착 상태는 학 시스템에 다음 4가지 조건이 동시에 성립될 때 발생할 수 있다.
-
상호 배제(mutual exclusion) : 최소한 하나의 자원이 비공유 모드로 점유되어야 한다.
- 비공유 모드에서는 한 번에 한 스레드만이 그 자원을 사용할 수 있다.
- 다른 스레드가 그 자원을 요청하면, 요청 스레드는 자원이 방출될 때까지 반드시 지연되어야 한다.
- 점유하며 대기(hold-and-wait) : 스레드는 최소한 하나의 자원을 점유한 채, 현재 다른 스레드에 의해 점유된 자원을 추가로 얻기 위해 반드시 대기해야 한다.
- 비선점(no preemption) : 자원들을 선점할 수 없어야 한다. 즉, 자원이 강제적으로 방출될 수 없고, 점유하고 있는 스레드가 태스크를 종료한 후 그 스레드에 의해 자발적으로만 방출될 수 있다.
- 순환 대기(circular wait) : 대기하고 있는 스레드의 집합 ${T_0, T_1,…,T_n}$에서 $T_0$는 $T_1$이 점유한 자원을 대기하고, $T_1$은 $T_2$가 점유한 자원을 대기하고,…, $T_n$은 $T_0$가 점유한 자원을 대기한다.
8.3.2 Resource-Allocation Graph
- 교착 상태는 시스템 자원 할당 그래프(system resource-allocation graph)라고 하는 방향(directed) 그래프로 더욱 정확하게 기술할 수 있다.
- 이 그래프는 정점(vertex) V의 집합과 간선(edge) E의 집합으로 구성된다.
- 정점 V의 집합은 시스템 내의 모든 활성 스레드의 집합인 $T={T_1, T_2, …, T_n}$과 시스템 내의 모든 자원 유형의 집합인 $R={R_1,R_2,…,R_m}$의 2가지 유형으로 구분된다.
- 스레드 $T_i$로부터 자원 유형 $R_j$로의 방향 간선(directed edge)은 $T_i \to R_j$로 표현한다.
- 이것은 스레드 $T_i$가 자원 유형 $R_j$의 인스턴스를 하나 요청하는 것으로 현재 이 자원을 기다리는 상태이다.
- $T_i \to R_j$를 요청 간선(request edge)이라 부른다.
- 스레드 $R_j$로부터 자원 유형 $T_i$로의 방향 간선(directed edge)은 $R_j \to T_i$로 표현한다.
- 이것은 자원 유형 $R_j$의 한 인스턴스가 스레드 $T_i$에 할당된 것을 의미한다.
- $R_j \to T_i$를 할당 간선(assignment edge)이라 부른다.
- 도식적으로, 각 스레드 $T_i$를 원으로 표현하고, 각 자우너 유형 $R_j$는 사각형으로 표현한다.
- 그리고 자원 유형 $R_j$가 한 개 이상의 인스턴스를 가질 때는 각 인스턴스를 사각형 내의 하나의 점으로 표현한다.
- 위 Figure 8.4의 자원 할당 그래프는 다음 상황을 묘사한다.
- 집합 $T$, $R$, $E$
- $T={T_1,T_2,T_3}$
- $R={R_1,R_2,R_3,R_4}$
- $E=T_1\ \to \ R_1,\ T_2\ \to \ R_3, $ $\ R_1\ \to \ T_2,\ R_2\ \to \ T_2,$ $\ R_2\ \to \ T_1,\ R_3\ \to \ T_3$
- 스레드 상태
- 스레드 $T_1$은 자원 유형 $R_2$의 인스턴스 1개를 점유하고, 자원 유형 $R_1$의 인스턴스 1개를 기다리며 대기한다.
- 스레드 $T_2$는 $R_1$과 $R_2$의 인스턴스를 각각 1개씩 점유하고, 자원 유형 $R_3$의 인스턴스 1개를 기다린다.
- 스레드 $T_3$는 $R_3$의 인스턴스 1개를 점유하고 있다.
- 위 Figure 8.5에서는 스레드 $T_1$, $T_2$, $T_3$는 교착 상태이다.
- 스레드 $T_2$는 스레드 $T_3$이 점유하고 있는 자원 $R_3$을 기다린다.
- 스레드 $T_3$는 반면에 스레드 $T_1$이나 $T_2$가 자원 $R_2$를 방출하기를 기다린다.
- 스레드 $T_1$은 $T_2$가 자원 $R_1$을 방출하기를 기다린다.
- 정리하면, 자원 할당 그래프에 사이클이 없다면, 시스템은 교착 상태가 아니다. 반면에, 사이클이 있다면 시스템은 교착 상태일 수도 있고 아닐 수도 있다.
8.4 Methods for Handling Deadlocks
- 교착 상태 문제를 처리하는 데는 다음과 같은 3가지 방법이 있다.
-
문제를 무시하고, 교착 상태가 시스템에서 절대 발생하지 않는 척한다.
- Linux와 Windows를 포함해 대부분의 운영체제가 사용하는 방법이다.
- 교착 상태를 처리하는 프로그램을 작성하는 것은 응용 개발자의 몫이다.
-
시스템이 결코 교착 상태가 되지 않도록 보장하기 위하여 교착 상태를 예방하거나 회피하는 프로토콜을 사용한다.
-
시스템이 교착 상태가 되도록 허용한 다음에 복구시키는 방법이 있다.
- 데이터베이스와 같은 일부 시스템이 이 해결안을 채택하여 교착 상태의 발생을 허용하고 복구 작업을 수행한다.
- 교착 상태가 발생하지 않도록 하기 위해 시스템은 교착 상태 예방(prevention), 또는 회피(avoidance) 기법의 하나를 사용할 수 있다.
- 교착 상태 예방(prevention) : 8.3.1절에서 언급한 필요조건 중 적어도 하나가 성립하지 않도록 보장하는 일련의 방법이다.
- 이들 방법은 자원이 어떻게 요청될 수 있는지를 제한함으로써 교착 상태를 예방한다.
- 교착 상태 회피(avoidance) : 스레드가 평생 요구하고 사용할 자원에 대한 부가적인 정보를 미리 제공할 것을 요구한다.
- 이러한 추가적인 지식을 가지고, 운영체제는 각 요청을 위해 그 스레드가 기다려야 할지 않을지를 결정할 수 있다.
- 교착 상태 예방(prevention) : 8.3.1절에서 언급한 필요조건 중 적어도 하나가 성립하지 않도록 보장하는 일련의 방법이다.
8.5 Deadlock Prevention
- 교착 상태가 발생하려면 4가지의 필요조건이 각각 성립해야 한다.
- 이들 조건 중에서 최소한 하나가 성립되지 않도록 보장함으로써, 교착 상태의 발생을 예방할 수 있다.
8.5.1 Mutual Exclusion
- 적어도 하나의 자원은 공유가 불가능한 자원이어야 하는 상호 배제 조건이 성립되어야 한다.
- 반면에, 공유 가능한 자원들은 배타적인 접근을 요구하지 않으며, 따라서 교착 상태에 관련될 수 없다.
- 일반적으로 상호 배제 조건을 거부함으로써 교착 상태를 예방하는 것은 불가능하다.
8.5.2 Hold and Wait
- 시스템에서 점유하며 대기 조건이 발생하지 않도록 하려면 스레드가 자원을 요청할 때마다 다른 자원을 보유하지 않도록 보장해야 한다.
- 우리가 사용할 수 있는 하나의 프로토콜은 각 스레드가 실행을 시작하기 전에 모든 자원을 요청하고 할당해야 한다.
- 한 대안 프로토콜은 스레드가 자원을 전혀 갖고 있지 않을 때만 자원을 요청할 수 있도록 허용한다.
- 스레드는 일부 자원을 요청하고 사용할 수도 있다.
- 스레드가 추가의 자원을 요청할 수 있으려면, 자신에게 할당된 모든 자원을 반드시 먼저 방출해야 한다.
8.5.3 No Preemption
- 이미 할당된 자원이 선점되지 않아야 한다는 조건을 성립되지 않을 것을 보장하기 위해, 우리는 다음의 프로토콜을 사용할 수 있다.
- 만일 어떤 자원을 점유하고 있는 스레드가 즉시 할당할 수 없는 다른 자원을 요청하면, 현재 점유하고 있는 모든 자원이 선점된다.
- 스레드는 자신이 요청하고 있는 새로운 자원은 물론 이미 점유하였던 옛 자원들을 다시 획득할 수 있을 때만 다시 시작된다.
- 대안으로, 한 스레드가 어떤 자원들을 요청하면, 우리는 이들이 사용 가능한지를 검사한다.
- 만약 사용 가능하다면, 이들을 할당한다.
- 만약 사용 불가능하다면, 그 자원들이 추가의 자원을 위해 대기하고 있는 어떤 다른 스레드에 할당되어 있는지를 검사한다.
- 이 프로토콜은 CPU 레지스터나 데이터베이스 트랜잭션처럼 그 상태가 쉽게 저장되고 후에 복원될 수 있는 자원에 종종 적용된다.
- 이것은 일반적으로 mutex 락과 세마포 같은 자원에는 적용될 수 있다.
8.5.4 Circular Wait
- 교착 상태 예방을 위해 지금까지 제시된 3가지 옵션은 대부분 상황에서 일반적으로 실용적이지 않다.
- 그러나 순환 대기 조건은 필요한 조건 중 하나를 무효화하여 실용적인 해결책을 제공할 수 있는 기회를 제공한다.
- 순환 대기 조건이 성립되지 않도록 하는 한 가지 방법은 모든 자원 유형에 전체적인 순서를 부여하여, 각 프로세스가 열거된 순서대로 오름차순으로 자원을 요청하도록 요구하는 것이다.
8.6 Deadlock Avoidance
- 교착 상태를 회피하는 다른 대안은 자원이 어떻게 요청될지에 대한 추가 정보를 제공하도록 요구하는 것이다.
- 각 스레드의 요청과 방출에 대한 완전한 순서를 파악하고 있다면, 우리는 각 요청에 대해서 가능한 미래의 교착 상태를 피하고자 스레드가 대기해야 하는지 여부를 결정할 수 있다.
- 각 요청에 대해 위와 같은 결정을 하려면 시스템은 현재 요청이 충족될 수 있는지 또는 반드시 대기해야 할 것인지를 결정하기 위해, 현재 가용 자원, 현재 각 스레드에 할당된 자원, 그리고 각 스레드가 앞으로 요청하거나 방출할 자원을 고려해야 한다.
- 가장 단순하고 제일 유용한 모델은 각 스레드가 자신이 필요로 하는 각 유형의 자원마다 최대 수를 선언하도록 요구하는 것이다.
- 각 스레드가 요청할 각 유형의 자원의 최대 수 정보를 미리 파악할 수 있다면, 우리는 시스템이 교착 상태에 들어가지 않을 것을 보장하는 알고리즘을 만들 수 있다.
- 교착 상태 회피 알고리즘은 시스템에 순환 대기 상황이 발생하지 않도록 자원 할당 상태를 검사한다.
- 자원 할당 상태는 가용 자원의 수, 할당된 자원의 수 그리고 스레드들의 최대 요구 수에 의해 정의된다.
8.6.1 Safe State
- 시스템 상태가 안전(safe)하다는 말은 시스템이 어떤 순서로든 스레드들이 요청하는 모든 자원을 교착 상태를 야기시키지 않고 차례로 모두 할당해 줄 수 있다는 것을 뜻한다.
- 즉, 시스템이 안전 순서(safe sequence)를 찾을 수 있다면 시스템은 안전하다고 말한다.
- 모든 스레드를 무사히 마칠 수 있는 시퀀스를 찾을 수 없으면 불안전(unsafe)하다고 한다.
- 기본 원칙은 시스템의 상태가 항상 안전 상태를 떠나지 않도록 고수하는 것이다.
8.6.2 Resource-Allocation Graph Algorithm
- 만약 각 자원 유형마다 단지 하나의 인스턴스를 갖는 자원 할당 시스템을 갖고 있다면, 우리는 교착 상태 회피를 위한 자원 할당 그래프의 변형을 사용할 수 있다.
- 요청 간선과 할당 간선에 추가하여, 예약 간선(claim edge)을 도입한다.
- 예약 간선 $T_i\to R_j$는 $P_i$가 미래에 자원 $R_j$를 요청할 것이라는 의미다.
- 간선의 방향은 점선(dashed line)으로 표시한다.
8.6.3 Banker’s Algorithm
- 은행원 알고리즘 시스템에서는 스레드가 시작할 때 스레드가 가지고 있어야 할 자원의 최대 개수를 자원 종류마다 미리 신고하여야 한다.
- 물론 이 숫자가 자원의 총 보유 수를 넘어서면 안 된다.
- 스레드가 자원들을 요청하면 시스템은 그것을 들어주었을 때 시스템이 계속 안전 상태에 머무르게 되는지 여부를 판단해야 한다.
- 계속 안전하게 된다면 그 요청을 들어준다.
- 그렇지 않다면 이 스레드의 요청은 허락이 안 된 채 다른 스레드가 끝날 때까지 기다리게 된다.
은행원 알고리즘에서 운영체제는 안전상태를 유지할 수 있는 요구만을 수락하고 불안전 상태를 초래할 사용자의 요구는 나중에 만족될 수 있을 때까지 계속 거절한다. 1
- 다음은 은행원 알고리즘을 구현하는 데 필요한 자료구조이다.
- 이 자료구조들은 시스템이 자원을 할당하고 있는 상태를 나타내게 된다.
- n : 스레드의 수
- m : 자원의 종류 수
- Available : 각 종류별로 가용한 자원의 개수를 나타내는 벡터
- $Available[j]=k$ : 현재 $R_j$를 k개 사용할 수 있다.
- Max : 각 스레드가 최대로 필요로 하는 자원의 개수를 나타내는 행렬
- $Max[i][j]=k$ : 스레드 $T_i$가 $R_j$를 최대 k개까지 요청할 수 있다.
- Allocation : 각 스레드에 현재 할당된 자원의 개수를 나타내는 행렬
- $Allocation[i][j]=k$ : 현재 스레드 $T_i$가 $R_j$를 k개 사용 중이다.
- Need : 각 스레드가 향후 요청할 수 있는 자원의 개수를 나타내는 행렬
- $Need[i][j]=k$ : 스레드 $T_i$가 향후 $R_j$를 k개까지 더 요청할 수 있다.
- $Need[i][j]=Max[i][j] - Allocation[i][j]$
8.7 Deadlock Detection
- 만일 시스템이 교착 상태 예방이나 교착 상태 방지 알고리즘을 사용하지 않는다면, 교착 상태가 발생할 수 있다.
- 이러한 환경에서는 시스템은 다음 알고리즘들을 반드시 지원해야 한다.
- 교착 상태가 발생했는지 결정하기 위해 시스템의 상태를 검사하는 알고리즘
- 교착 상태로부터 회복하는 알고리즘
8.7.1 Single Instance of Each Resource Type
- 모든 자원이 한 개의 인스턴스만 있다면, 대기 그래프(wait-for graph)라고 하는, 자원 할당 그래프의 변형을 사용해 교착 상태 탐지 알고리즘을 정의할 수 있다.
- 자원 할당 그래프로부터 자원 유형의 노드를 제거하고 적절한 간선들을 결합함으로써 대기 그래프를 얻을 수 있다.
- 대기 그래프에서 $T_i$에서 $T_j$로의 간선은 프로세스 $T_j$가 가지고 있는 자원들에 대해, 프로세스 $T_i$가 그 자원이 필요하여 방출하기를 기다리는 것이다.
- 간선 $T_i\to T_j$는 해당 자원 할당 그래프가 자원 $R_q$에 대해 2개의 간선 $T_i\to R_q$와 $R_q\to T_j$를 포함하는 경우에만 대기 그래프에 존재한다.
8.7.2 Several Instances of a Resource Type
- 대기 그래프는 종류마다 자원이 여러 개씩 존재하는 상황에서는 사용할 수 없다.
- 시시각각 내용이 달라지는 자료구조를 사용하는 알고리즘을 사용해 교착 상태를 탐지할 수 있다.
- Available: 각 종류의 자원이 현재 몇 개가 가용한지를 나타내는 벡터로 크기가 m이다.
- Allocation : 각 스레드에 현재 할당된 자원의 개수를 나타내는 행렬로 크기가 n x m 이다.
- Request : 각 스레드가 현재 요청 중인 자원의 개수를 나타내는 행렬로 크기가 n x m이다.
Request[i][j]==k
라면 현재 $T_i$가 $R_j$를 k개 요청 중임을 뜻한다.
8.8 Recovery form Deadlock
- 탐지 알고리즘이 교착 상태가 존재한다고 결정하면, 여러 가지 처리 방법이 있다.
- 한 가지 방법은 교착 상태가 발생한 것을 운영자에게 통지해, 운영자가 수작업으로 처리하게 하는 것이다.
- 다른 방법은 시스템이 자동으로 교착 상태로부터 회복하게 하는 것이다.
- 교착 상태를 깨뜨리는 데는 2가지 방법이 있다.
- 한 가지 방법은 순환 대기를 깨뜨리기 위해 단순히 1개 이상의 스레드를 중지(abort)시키는 것이다.
- 다른 방법은 교착 상태에 있는 하나 이상의 스레드들로부터 자원을 선점하는 것이다.
댓글남기기