За последние 15 лет я перечитывал Херлихи и Винг много раз. Это очень трудно читать. И это прискорбно, потому что, хотя есть некоторые тонкости по краям, основная идея на самом деле вполне разумна.
Вкратце: линеаризуемость подобна сериализуемости, но с дополнительным требованием, чтобы сериализация учитывала дополнительные ограничения порядка между транзакциями. Цель состоит в том, чтобы позволить вам строго рассуждать об отдельной атомарной структуре данных, а не рассуждать обо всей системе сразу.
Также легко добиться линеаризации: просто свяжите мьютекс с объектом, который вы хотите линеаризовать. Каждая транзакция в этом объекте начинается с блокировки мьютекса и заканчивается разблокировкой мьютекса.
Вот определения, которые я буду использовать:
Система является сериализуемой, если задан набор транзакций над набором данных, любой результат выполнения транзакций такой же, как если бы транзакции были выполнены в некотором последовательном порядке, а операции внутри каждой транзакции содержатся в их транзакции в заказе. указывается кодом транзакции.
Сериализуемость не допускает появления чередования операций между различными транзакциями и требует, чтобы выбранный порядок транзакций удовлетворял причинности (если транзакция A записывает значение x, а транзакция B считывает значение x, записанное A, тогда транзакция A должна предшествовать транзакции B в выбранный серийный заказ.) Но он ничего не говорит о каких-либо других ограничений на порядок транзакций (в частности, он ничего не говорит о процессах и порядке, в котором процессы воспринимают события).
Есть еще одна связанная идея, которая добавляет ограничения относительно порядка, в котором процессы выполняют операции (но не говорит о транзакциях только отдельных операций чтения / записи):
Система является последовательной последовательностью, если результат любого выполнения такой же, как если бы операции всех процессов были выполнены в некотором последовательном порядке, и операции каждого отдельного процесса появляются в этой последовательности в порядке, указанном его программой. ( Лампорт, «Как создать многопроцессорный компьютер, который правильно выполняет многопроцессорные программы», IEEE T Comp 28: 9 (690-691), 1979 ).
В определении последовательной согласованности подразумевается, что мы принимаем только последовательные порядки, когда для каждой области памяти (объекта) индуцированный последовательный порядок операций подчиняется правилу, согласно которому значение, возвращаемое каждой операцией чтения в расположение, x
должно быть тем же значением, которое было записано непосредственно предшествующая операция записи в местоположение x
в последовательном порядке.
Линеаризуемость имеет благие намерения: (а) объединить понятие транзакций (от сериализации) с понятием, что процессы ожидают завершения операций, которые они выдают, в порядке (от последовательной согласованности) и (б) сужения критериев корректности, чтобы говорить о каждом объект в изоляции, а не заставлять вас рассуждать о системе в целом. (Я хотел бы сказать, что реализация моего объекта является правильной даже в системе, где есть другие объекты, которые не являются линеаризуемыми.) Я полагаю, что Херлихи и Винг, возможно, пытались строго определить монитор .
Часть (а) является «простой»: последовательное требование, подобное согласованности, должно заключаться в том, чтобы транзакции с объектом, выданным каждым процессом, появлялись в результирующей последовательности в порядке, указанном программой. Похожим на сериализацию требованием было бы, чтобы все транзакции на объекте были взаимоисключающими (могут быть сериализованы).
Сложность проистекает из цели (б) (способность говорить о каждом объекте независимо от всех других).
В системе с несколькими объектами возможно, что операции над объектом B накладывают ограничения на порядок, в котором мы считаем, что операции были вызваны на объекте A. Если мы смотрим на всю историю системы, то мы будем ограничены определенными последовательными порядками, и нужно будет отвергнуть других. Но мы хотели критерии корректности, которые мы могли бы использовать изолированно (рассуждая о том, что происходит с объектом А, не обращаясь к истории глобальной системы).
Например: предположим, что я пытаюсь спорить о правильности объекта A, который является очередью, предположим, что объект B является местом в памяти, и предположим, что у меня есть следующие истории выполнения: Поток 1: A.enqueue (x), A. dequeue () (возвращает y). Поток 2: A.enqueue (y), A.dequeue () (возвращает x). Существует ли чередование событий, которое позволило бы правильно реализовать эту очередь? Да:
Thread 1 Thread 2
A.enqueue(x) ...
... A.enqueue(y)
... A.dequeue() (returns x)
A.dequeue(y) (returns y) ...
Но что теперь, если история ( включая объект B ): B начинается со значения 0. Поток 1: A.enqueue (x), A.dequeue () (возвращает y), B.write (1). Поток 2: B.read () (возвращает 1) A.enqueue (y), A.dequeue () (возвращает x).
Thread 1 Thread 2
A.enqueue(x) ...
A.dequeue() (returns y) ... (uh oh!)
B.write(1) ...
... B.read() (returns 1)
... A.enqueue(y)
... A.dequeue() (returns x)
Теперь мы хотели бы, чтобы в нашем определении «правильности» говорилось, что эта история указывает на то, что либо наша реализация A содержит ошибки, либо наша реализация B содержит ошибки, потому что не существует сериализации, которая «имеет смысл» (либо Thread 2 должен прочитать значение из B, которое еще не было записано, или Поток 1 должен удалить из A значение, которое еще не было помещено в очередь.) Таким образом, в то время как наша первоначальная сериализация транзакций на A казалась разумной, если бы наша реализация допускает историю, подобную второй, тогда она явно неверна.
Таким образом, ограничения, которые добавляет линеаризация, вполне разумны (и необходимы даже для простых структур данных, таких как очереди FIFO.) Это такие вещи, как: «ваша реализация должна запретить dequeue () значение, которое не будет помещено в очередь () до тех пор, пока в течение некоторого времени будущее." Линеаризуемость довольно проста (и естественна) для достижения: просто ассоциируйте мьютекс с вашим объектом, и каждая транзакция начинается с блокировки и заканчивается разблокировкой. Рассуждение о линеаризуемости начинает усложняться, когда вы пытаетесь реализовать свою атомарность с помощью неблокирующих, без блокировок или без ожидания процедур вместо простых мьютексов.
Если вас интересуют некоторые ссылки на литературу, я обнаружил следующее (хотя я думаю, что обсуждение «реального времени» - это одна из «красных селедок», которые затрудняют линеаризуемость по сравнению с необходимостью.) Https: // stackoverflow.com/questions/4179587/difference-between-linearizability-and-serializability