(Lispex)sicp.io
3.10 · 직렬 실행과 배제

serializer는 한 상태 전이가 끝난 뒤 다음 전이를 시작하게 한다.

잠금 셀과 test-and-set 경계는 겹친 진입을 거부하고 serializer는 공유 상태를 바꾸는 프로시저를 같은 잠금으로 감쌉니다.

생각해 볼 질문

한 갱신이 상태를 읽은 뒤 다른 갱신이 끝나고 나서야 쓰는 일을 막으려면 무엇을 보호해야 할까요?

  • test-and-set!이 이전 잠금 상태를 반환한다고 읽기
  • 획득 실패와 해제 뒤 재시도를 구분하기
  • 공유 잠금 하나로 상태 변경 프로시저 감싸기
  • 오래된 읽기의 갱신 손실과 직렬화된 유한 실행 비교하기

The lock is a one-cell mutable list. test-and-set! reports whether the cell was already true; otherwise it changes the cell to true and reports the previous false state. The first acquisition therefore succeeds, an overlapping attempt fails, and a retry after clear! succeeds. SICP treats test-and-set! as an atomic implementation boundary. This browser program models that boundary as one named operation; it does not create threads or establish machine-level atomicity.

make-serializer accepts a shared lock and returns a procedure wrapper. The wrapper acquires before calling the state-changing procedure and clears after receiving its result. In the shipped finite schedule, the serialized deposit finishes before the withdrawal reads balance, so both updates remain in the final value 90. The comparison program does not prove fairness, deadlock freedom, exception safety, or the outcome of every possible concurrent schedule.

리스펙스 · SICP 코드SICP에 필요한 Scheme 호환 문법을 리스펙스 SICP 프로필로 실행합니다.
(begin
  (define (test-and-set! cell)
    (if (car cell)
        #t
        (begin
          (set-car! cell #t)
          #f)))
  (define (clear! cell) (set-car! cell #f))
  (define lock (list #f))
  (define first-acquire (not (test-and-set! lock)))
  (define overlapping-acquire (not (test-and-set! lock)))
  (clear! lock)
  (define retry-acquire (not (test-and-set! lock)))
  (list first-acquire
        overlapping-acquire
        retry-acquire
        (car lock)))
리스펙스 학습용 런타임리스펙스 SICP 프로필 1.0.0
리스펙스 SICP 런타임 불러오는 중
리스펙스 · SICP 코드UTF-8 468 / 1,048,576바이트
예제
결과
출력
진단
보이는 실행 흐름0 / 0 개의 실행 이벤트
    이 브라우저 결과는 리스펙스 바우치나 권한이 아닙니다.wasm —
    예상 관찰

    The first program returns (#t #f #t #t). The second returns (80 110 90 90 #f).

    실행 흐름에서 볼 점

    In the first run, locate the two set-car! transitions separated by clear!, and distinguish the overlapping call that performs no mutation. In the second, compare the two stale reads inside lost-update with the serialized wrapper that acquires, completes one balance assignment, releases, and only then lets the next wrapper read. The bounded trace describes these explicit sequential schedules only.

    직접 해보기

    힌트를 보기 전에 프로그램을 바꿔 보세요.

    Set the shared lock to true immediately before serialized-deposit. Predict its result and balance, then clear the lock and call the deposit again.

    힌트 하나 보기

    A busy wrapper does not call its protected procedure. After clear!, the same wrapper can acquire and perform the update.