식사하는 철학자 문제 문서의 검증 코드다. if __name__ == "__main__": 아래가 자체 테스트다.

"""식사하는 철학자: (1) 모두 왼쪽 포크부터 잡으면 교착상태가 생기는 순서를 재현하고,
(2) 방에 최대 4명만 들이는 해법(Stallings 그림 6.13)과 (3) 포크 번호 순서 해법이 실제로 멈추지 않는지 돌려 본다."""
import threading

N, MEALS = 5, 300


def naive_deadlock():
    forks = [threading.Lock() for _ in range(N)]
    for i in range(N):
        forks[i].acquire()                       # 다섯 명이 동시에 왼쪽 포크를 잡은 순간
    # 이제 누구도 오른쪽 포크 (i+1)%N을 얻을 수 없다
    return [forks[(i + 1) % N].acquire(timeout=0.05) for i in range(N)]


def run(strategy):
    forks = [threading.Lock() for _ in range(N)]
    room = threading.Semaphore(N - 1)
    eaten = [0] * N

    def phil(i):
        left, right = i, (i + 1) % N
        for _ in range(MEALS):
            if strategy == "room":
                room.acquire()
                forks[left].acquire(); forks[right].acquire()
            else:  # "order": 번호가 작은 포크부터
                a, b = sorted((left, right))
                forks[a].acquire(); forks[b].acquire()
            eaten[i] += 1
            forks[right].release(); forks[left].release()
            if strategy == "room":
                room.release()

    ts = [threading.Thread(target=phil, args=(i,)) for i in range(N)]
    for t in ts: t.start()
    for t in ts: t.join(timeout=30)
    return not any(t.is_alive() for t in ts), eaten


if __name__ == "__main__":
    assert naive_deadlock() == [False] * N
    for s in ("room", "order"):
        ok, eaten = run(s)
        print(s, ok, eaten)
        assert ok and eaten == [MEALS] * N
    print("ALL CHECKS PASSED")