독자-저자 문제 문서의 검증 코드다. if __name__ == "__main__": 아래가 자체 테스트다.

"""독자 우선 독자-저자 해법(Stallings 그림 5.22)을 실제 스레드로 돌려,
(1) 저자는 언제나 혼자 쓰고, (2) 저자가 쓰는 동안 독자가 없고, (3) 독자는 여럿이 함께 읽을 수 있음을 확인한다."""
import threading
import time

readcount = 0
x = threading.Semaphore(1)      # readcount 보호
wsem = threading.Semaphore(1)   # 쓰기 권한
state = {"readers": 0, "writers": 0, "max_readers": 0, "violations": 0}
guard = threading.Lock()        # 검사용 기록 보호(해법의 일부가 아님)


def check():
    if state["writers"] > 1 or (state["writers"] and state["readers"]):
        state["violations"] += 1


def reader():
    global readcount
    for _ in range(200):
        x.acquire()
        readcount += 1
        if readcount == 1:
            wsem.acquire()          # 첫 독자가 저자를 막는다
        x.release()
        with guard:
            state["readers"] += 1
            state["max_readers"] = max(state["max_readers"], state["readers"])
            check()
        time.sleep(0.0002)          # 읽는 중
        with guard:
            state["readers"] -= 1
        x.acquire()
        readcount -= 1
        if readcount == 0:
            wsem.release()          # 마지막 독자가 저자를 풀어 준다
        x.release()


def writer():
    for _ in range(50):
        wsem.acquire()
        with guard:
            state["writers"] += 1
            check()
        time.sleep(0.0002)          # 쓰는 중
        with guard:
            state["writers"] -= 1
        wsem.release()


if __name__ == "__main__":
    ts = [threading.Thread(target=reader) for _ in range(4)] + [threading.Thread(target=writer) for _ in range(2)]
    for t in ts: t.start()
    for t in ts: t.join(timeout=60)
    assert not any(t.is_alive() for t in ts)
    print(state)
    assert state["violations"] == 0
    assert state["max_readers"] >= 2     # 여러 독자가 함께 읽은 적이 있다
    print("ALL CHECKS PASSED")