sicp.io
3.4.2 · Сериализация и исключение

Сериализатор как граница перехода состояния

Ячейка блокировки и граница test-and-set не пускают второй вход, а сериализатор оборачивает изменяющие состояние процедуры.

Вопрос для размышления

Что необходимо защитить, чтобы обновление не могло прочитать состояние и завершиться уже после того, как другое обновление его изменило?

  • Понимание того, что test-and-set! возвращает предыдущее состояние блокировки
  • Разделение неудачи при захвате, освобождения блокировки и повторной попытки
  • Оборачивание изменяющей состояние процедуры единой общей блокировкой
  • Сравнение потери обновления из-за устаревшего чтения с сериализованным конечным расписанием

Блокировка представляет собой мутабельный список из одной ячейки. Процедура test-and-set! сообщает, содержала ли ячейка значение true, а в противном случае устанавливает в ячейку значение true и сообщает о предыдущем значении false. Поэтому первый захват проходит успешно, пересекающаяся попытка завершается неудачей, а повторная попытка после clear! завершается успешно. Эта браузерная программа моделирует атомарную границу реализации из SICP как одну именованную операцию в конечном расписании.

Процедура make-serializer принимает общую блокировку и возвращает обертку для процедуры. Эта обертка выполняет захват перед вызовом изменяющей состояние процедуры и сбрасывает блокировку после получения ее результата. В предоставленном конечном расписании сериализованная операция deposit завершается до того, как операция withdrawal прочитает баланс balance, поэтому оба обновления сохраняются в итоговом значении 90. Урок фиксирует именно это расписание и конечное состояние.

Код SICP468 из 1,048,576 байт UTF-8
Примеры
Результат
Вывод
Значение
Диагностика
Трасса выполнения0 / 0 событий
    Запуски происходят внутри браузера с отображением результата программы и трассы выполнения.
    Ожидаемый результат

    Первая программа возвращает (#t #f #t #t). Вторая программа возвращает (80 110 90 90 #f).

    На что обратить внимание в трассе

    В первом запуске найдите два перехода set-car!, разделенные операцией clear!, и определите пересекающийся вызов, который не выполняет мутации. Во втором запуске сравните два устаревших чтения внутри lost-update с сериализованной оберткой, которая захватывает блокировку, выполняет одно присваивание переменной balance, освобождает блокировку и только затем разрешает чтение следующей обертке. Трасса выполнения с фиксированным ограничением описывает только эти явные последовательные расписания.

    Попробуйте сами

    Измените программу и сравните результат.

    Установите общую блокировку в значение true непосредственно перед serialized-deposit. Предскажите результат и значение balance, затем очистите блокировку и вызовите deposit снова.

    Показать подсказку

    Занятая обертка не вызывает защищаемую процедуру. После операции clear! та же обертка может захватить блокировку и выполнить обновление.

    Завершить этот урок

    В этой главе пройдено 0 из 21 урока0%