어뗜 경우에 데드락과 같이 활동성에 문제가 되는지 살펴보고, 이런 상황을 미연에 방지하는 방법
식시하는 철학자 문제
데드락이 발생하는 경우
모든 철학자가 왼쪽 포크를 든다면 아무도 오른쪽 포크를 들 수 없어 데드락이 발생한다.
데드락을 방지하는 경우
뮤텍스 락을 획득하면 임계 영역으로 진입해 왼쪽과 오른쪽의 포크를 모두 들고 먹은 뒤, 다시 뮤텍스의 락을 획득하면 임계 영역으로 진입해 왼쪽과 오른쪽의 철학자를 깨운다.
mutex
를 사용하고,
왼쪽과 오른쪽의 포크 쌍에 해당하는 이진 세마포어의 배열 s[N]
을 사용한다.test(LEFT)
, test(RIGHT)
을 할까?
인터페이스의 관점으로 볼 땐 sleep() 이나 join() 상태의 스레드를 interrupt() 을 사용해 깨운 것과 같지 않을까?
자바의 interrupt() 도 마찬가지로 세마포어를 사용해 스레드 간 통신하고 있을까?
https://github.com/openjdk/jdk/blob/master/src/hotspot/share/runtime/javaThread.cpp#L538
https://github.com/openjdk/jdk/blob/master/src/hotspot/os/posix/os_posix.cpp#L1628
데이터베이스 시스템의 데드락
JVM 의 데드락
데드락이 걸린 스레드가 어떤 스레드인지에 따라
- 애플리케이션 자체가 완전히 멈춰버릴 수도 있고
[예시] 2개의 스레드가 서로 다른 순서로 락을 확보할 때 발생 가능한 데드락
public class LeftRightDeadlock {
private final Object left = new Object();
private final Object right = new Object();
public void leftRight() {
synchronized (left) {
synchronized (right) {
doSomething();
}
}
}
public void rightLeft() {
synchronized (right) {
synchronized (left) {
doSomethingElse();
}
}
}
void doSomething() {
}
void doSomethingElse() {
}
}
프로그램을 작성할 때 데드락을 방지할 수 있을 만큼 락을 사용하는 순서를 충분히 조절하지 못할 수도 있다.
[예시] 함수에 넘겨주는 인자의 순서에 따라 락 순서가 달라질 때 발생 가능한 데드락
public static void transferMoney(Account fromAccount,
Account toAccount,
DollarAmount amount)
throws InsufficientFundsException {
synchronized (fromAccount) {
synchronized (toAccount) {
if (fromAccount.getBalance().compareTo(amount) < 0)
throw new InsufficientFundsException();
else {
fromAccount.debit(amount);
toAccount.credit(amount);
}
}
}
}
- 스레드 A: transferMoney(myAccount, yourAccount, 10); // myAccount -> yourAccount
- 스레드 B: transferMoney(yourAccount, myAccount, 20); // yourAccount -> myAccount