Joe Duffy дает 6 правил, описывающих модель памяти CLR 2.0+ (это фактическая реализация, а не любой стандарт ECMA) Я пишу с моей попытки понять это, в основном, как способ резинового уклонения, но если я ошибусь в своей логике, по крайней мере, кто-то здесь сможет поймать его, прежде чем это вызовет мое горе.
- Правило 1: Зависимость данных от нагрузки и магазины никогда не нарушаются.
- Правило 2: У всех магазинов есть семантика выпуска, т.е. загрузка или хранение могут перемещаться после один.
- Правило 3: Все летучие нагрузки приобретать, то есть без нагрузки или хранения двигаться до одного.
- Правило 4: Нет нагрузок и магазины могут когда-либо пересекать полный барьер (например, Thread.MemoryBarrier, блокировка приобретать, блокировать. Обмен, Interlocked.CompareExchange и т.д.).
- Правило 5: загрузка и хранение в кучу никогда не могут быть введены.
- Правило 6: Загрузка и сохранение могут быть удалены только при объединении смежных нагрузок и магазины из/в том же месте.
Я пытаюсь понять эти правила.
x = y
y = 0 // Cannot move before the previous line according to Rule 1.
x = y
z = 0
// equates to this sequence of loads and stores before possible re-ordering
load y
store x
load 0
store z
Посмотрев на это, кажется, что нагрузка 0 может быть перенесена до загрузки y, но магазины не могут быть повторно заказаны вообще. Поэтому, если поток видит z == 0, тогда он также увидит x == y.
Если y было изменчивым, тогда загрузка 0 не могла перемещаться до загрузки y, иначе это может произойти. Волатильные магазины, похоже, не имеют каких-либо специальных свойств, никакие магазины не могут быть переупорядочены по отношению друг к другу (что является очень сильной гарантией!)
Полные барьеры подобны линии в песке, которые загружаются, а магазины не могут перемещаться.
Не знаю, что означает правило 5.
Я предполагаю, что правило 6 означает, что вы делаете:
x = y
x = z
Тогда CLR может удалить как нагрузку, так и первую ячейку памяти до x.
x = y
z = y
// equates to this sequence of loads and stores before possible re-ordering
load y
store x
load y
store z
// could be re-ordered like this
load y
load y
store x
store z
// rule 6 applied means this is possible?
load y
store x // but don't pop y from stack (or first duplicate item on top of stack)
store z
Что делать, если y была изменчивой? Я не вижу ничего в правилах, которые запрещают выполнение вышеуказанной оптимизации. Это не нарушает блокировку с двойной проверкой, потому что блокировка() между двумя идентичными условиями предотвращает перемещение нагрузок в смежные позиции и согласно правилу 6, что единственный раз, когда они могут быть устранены.
Итак, я думаю, что я понимаю все, кроме правила 5, здесь. Кто-нибудь хочет просветить меня (или исправить меня или добавить что-нибудь к любому из вышеперечисленного?)