Согласованность релизов — одна из моделей согласованности на основе синхронизации, используемых в параллельном программировании (например, в распределенной общей памяти , распределенных транзакциях и т. д.).
В современных параллельных вычислительных системах согласованность памяти должна поддерживаться, чтобы избежать нежелательных результатов. Строгие модели согласованности, такие как последовательная согласованность , интуитивно составлены, но могут быть довольно ограничительными с точки зрения производительности, поскольку они отключают параллелизм на уровне инструкций , который широко применяется в последовательном программировании. Для достижения лучшей производительности исследуются некоторые ослабленные модели, а согласованность выпуска является агрессивной попыткой ослабления. [1]
Последовательная согласованность может быть достигнута просто за счет аппаратной реализации, в то время как согласованность выпуска также основана на наблюдении, что большинство параллельных программ правильно синхронизированы. На уровне программирования синхронизация применяется для четкого планирования определенного доступа к памяти в одном потоке, который должен происходить после другого. При доступе к синхронизированной переменной оборудование должно убедиться, что все записи, локальные для процессора, были распространены на все другие процессоры, и все записи с других процессоров видны и собраны. В модели согласованности выпуска действия входа и выхода из критической секции классифицируются как получение и освобождение , и для любого случая в программу должен быть помещен явный код, показывающий, когда выполнять эти операции .
В общем случае распределенная общая память является согласованной по выпуску, если она подчиняется следующим правилам: [2]
1. Перед выполнением доступа к общей переменной все предыдущие операции по получению данных этим процессором должны быть завершены.
2. Перед выполнением освобождения все предыдущие операции чтения и записи в рамках этого процесса должны быть завершены.
3. Доступы к получению и освобождению должны быть согласованы с процессором .
Если вышеуказанные условия выполнены и программа правильно синхронизирована (т. е. процессоры правильно реализуют acquire и release), результаты любого выполнения будут точно такими же, как если бы они были выполнены в соответствии с последовательной согласованностью. Фактически, доступы к общим переменным разделяются на атомарные блоки операций примитивами acquire и release, так что гонки и чередование между блоками будут предотвращены.
Освобождение от блокировки можно рассматривать как тип синхронизации освобождения. Предположим, что операция цикла выполняется с использованием кода, показанного справа. Два потока намереваются войти в критическую секцию и прочитать самое последнее значение a , а затем выйти из критической секции. Код показывает, что поток 0 первым получает блокировку и входит в критическую секцию. Для корректного выполнения P1 должен прочитать последнее значение a , записанное P0. В этом случае в критической секции одновременно может находиться только один поток. Таким образом, сама синхронизация гарантирует, что успешное получение блокировки в P1 происходит после освобождения блокировки P0. Кроме того, необходимо обеспечить порядок S2 -> S3, поскольку P0 должен передать новое значение a в P1. По той же причине S5 должен произойти после S4. [3]
Корректность не затрагивается, если доступ к памяти осуществляется после проблемы разблокировки до завершения разблокировки или доступ к памяти осуществляется до проблемы блокировки после получения блокировки. Однако код в критической секции не может быть выдан до завершения получения блокировки, поскольку взаимное исключение не может быть гарантировано.
Синхронизация после ожидания — это еще одна форма реализации согласованности выпуска. Как показано в коде справа, корректность может быть обеспечена, если операции после ожидания выполняются только после завершения доступа ко всей памяти, особенно сохранение в «a». Кроме того, операция чтения не должна выполняться до завершения операции ожидания. S2 действует как синхронизация выпуска, а S3 действует как синхронизация приобретения. Поэтому S2 необходимо предотвратить выполнение предыдущего выполнения после себя, а S3 необходимо предотвратить выполнение любого последующего выполнения до него. S2 не требуется предотвращать выполнение последующего выполнения до него. Аналогично, S3 не требуется предотвращать выполнение любого предыдущего выполнения после него.
Ленивая согласованность выпуска — это дальнейшая оптимизация согласованности выпуска. Она предполагает, что поток, выполняющий доступ получения, не нуждается в значениях, записанных другими потоками, пока доступ получения не будет завершен. Следовательно, все поведение согласованности может быть отложено, а время распространения записи может быть настроено. [4]
Рассмотрим сценарии, описанные на изображении справа. Этот случай показывает, когда распространение записи выполняется в системе с когерентным кэшем на основе модели согласованности выпуска. Переменная datum полностью распространяется до распространения datumIsReady. Но значение datum не требуется до тех пор, пока не будет получен доступ к синхронизации в P1, и его можно распространить вместе с datumIsReady, не нанося вреда результату программы.
Второе изображение показывает, что происходит, когда применяется ленивая согласованность релиза. Принимая во внимание этот сценарий, все значения, записанные до синхронизации релиза, задерживаются и распространяются вместе с распространением самого доступа к релизу. Следовательно, datum и datumIsReady распространяются вместе в точке релиза.
«TreadMarks» [5] — это фактическое применение принципа ленивого выпуска.
В некоторых случаях ленивая согласованность релиза может превзойти согласованность релиза. Если есть система с небольшой пропускной способностью между процессорами или она сильно страдает от более высоких накладных расходов из-за частого распространения небольших блоков данных по сравнению с редким распространением больших блоков данных, LRC может действительно помочь производительности.
Предположим, что система использует абстракцию разделяемой памяти на программном уровне, а не фактическую аппаратную реализацию. В этой системе распространение записи выполняется на уровне детализации страницы, что делает чрезвычайно дорогим распространение целой страницы, когда изменяется только один блок на этой странице. Поэтому распространение записи задерживается до тех пор, пока не будет достигнута точка синхронизации выпуска, и вся страница будет изменена в это время, и вся страница будет распространена.
LRC требует выполнения распространения записи в большом объеме в точке освобождения синхронизации. Распространение такого большого количества записей в целом замедлит доступ освобождения и последующий доступ получения. Следовательно, это вряд ли может улучшить производительность системы когерентности аппаратного кэша.
Согласованность выпуска требует от программистов большего по сравнению со слабым порядком. Они должны маркировать доступы синхронизации как приобретения или освобождения, а не просто как доступы синхронизации. Подобно слабому порядку, согласованность выпуска позволяет компилятору свободно переупорядочивать загрузки и сохранения, за исключением того, что они не могут перемещаться вверх после синхронизации приобретения и не могут перемещаться вниз после синхронизации выпуска. Однако преимущество гибкости и производительности согласованности выпуска достигается за счет требования правильной идентификации доступа синхронизации и идентификации его как приобретений и освобождений. В отличие от слабого порядка, доступ синхронизации не может быть легко идентифицирован только по кодам операций инструкций. Следовательно, бремя правильной идентификации доступа синхронизации приобретения и освобождения лежит на плечах программистов. [3] [6]
Для согласованности процессора все процессы видят записи с каждого процессора в том порядке, в котором они были инициированы. Записи с разных процессоров могут не отображаться в том же порядке, за исключением того, что записи в одно и то же место будут отображаться в том же порядке везде. По сравнению с согласованностью процессора согласованность выпуска более расслаблена, поскольку она не навязывает порядок между хранилищами, который происходит при согласованности процессора. Она не следует интуиции программистов, поскольку она относительно менее ограничительна для оптимизаций компилятора.