Volatile.Write свежесть гарантия

2

Документация для Volatile.Write гласит следующее:

Записывает указанную ссылку на объект в указанное поле. В системах, которым это требуется, вставляется барьер памяти, который не позволяет процессору переупорядочивать операции с памятью следующим образом: Если чтение или запись появляются перед этим методом в коде, процессор не может переместить его после этого метода.

а также

значение T
Ссылка на объект для записи. Ссылка пишется сразу, чтобы она была видна всем процессорам компьютера.

Но похоже, что цитаты 1 и 2 противоречивы.

Чтобы вторая цитата была верной, я бы подумал, что первую цитату нужно будет изменить следующим образом:

Если чтение или запись появляется перед после этого метода в коде, процессор не может переместить его после того, как перед этим методом.

Означает ли Volatile.Write что другие потоки гарантированно заберут запись вовремя, или вторая цитата вводит в заблуждение?

Мне кажется, что все эти "изменчивые"/"барьеры памяти", кажется, сосредоточены на том, чтобы гарантировать, что если записи подвергаются воздействию других потоков, они отображаются в правильном порядке, но я не могу найти то, что на самом деле заставить их быть разоблаченными.

Я понимаю, что может быть трудно/невозможно сразу представить записи в другие потоки, но без изменяемых операций записи/чтения бывают случаи, когда записи выставляются никогда. Таким образом, кажется, должен быть способ обеспечить доступность записей "в конце концов", но я не уверен, что это такое. Это то, что записи всегда отображаются в .NET но чтения могут быть кэшированы? И если да, то Volatile.Read останавливает это поведение кеширования?

(Обратите внимание, что я прочитал Джозеф Албахари, посвященный многопоточности в С#, который предполагает наличие явных барьеров памяти перед чтением и после записи, хотя неясно, почему даже это должно быть эффективным, поскольку документация для Thread.MemoryBarrier, похоже, не явно сказать, что записи показываются в других потоках).

Теги:
multithreading
memory-barriers

2 ответа

3

Вы немного неправильно понимаете концепцию барьеров. Как вы написали

Ссылка на объект для записи. Ссылка пишется сразу, чтобы она была видна всем процессорам компьютера.

Таким образом, действительно важным элементом здесь является процессор, а не поток.

Таким образом, существуют процессоры, кэши процессоров, буферы хранения и очереди аннулирования.
Когда процессор записывает что-то в память, это выглядит так или похоже на это Изображение 174551

Тема находится на уровне буфера хранилища. Как видите, когда вы что-то пишете или читаете, происходит много вещей, и это происходит не сразу для всех процессоров в системе. В начале команда чтения или записи помещается в буфер хранилища процессора, и эти команды могут быть переупорядочены, другими словами, выполняются процессором в другом порядке.

Хотя это происходит, другие процессоры не знают об изменениях, если операция находится в режиме записи, а работающий в данный момент процессор не знает об изменениях, внесенных другими процессорами.

Когда вы устанавливаете барьер, это означает, что операции в буфере хранения или очереди аннулирования должны быть завершены до того, как может быть выполнено любое чтение или запись. Это необходимо для актуализации кэшей ЦП между процессорами. Таким образом, в принципе нет никакой механики для синхронизации любых данных между потоками, мы синхронизируем данные между процессорами.

Когда поток A записывает что-то в процессор 1, а поток B читает что-то в процессоре 1, они оба начинают с просмотра буфера памяти в первую очередь, поэтому они читают фактические данные, независимо от того, установлены ли какие-либо барьеры или нет.

Это просто обзор механики, может быть, я ошибаюсь в некоторых деталях. Вы можете найти полную информацию, если прочитаете о протоколе MESI, этом PDF- файле с объяснением очередей аннулирования и буферов хранения.

2

Я согласен с вами, что описание в документации MSDN немного сбивает с толку. Я бы сказал, что "немедленно" является сильным словом здесь, а также в отношении любого предмета, связанного с параллельными процессами. Результат не будет виден сразу, но документация не говорит об этом - в нем говорится, что значение будет записано немедленно, то есть, как только все предыдущие операции загрузки/сохранения станут глобально видимыми, операция сохранения для записи значения будет немедленно начато.

Что касается барьеров памяти, они только могут дать гарантию предварительного раскрытия операций (глобальная видимость), потому что по сути барьеры памяти - это инструкции, с которыми сталкивается ЦП, что заставляет ЦП "ждать" для получения всех ожидающих операций загрузки/сохранения в глобальном масштабе. в то время как момент глобальной видимости значения, записанного Volatile.Write является ни барьером, ни проблемой Volatile.Write.

Теперь о предложении использовать барьер в программировании без блокировки. Конечно, это имеет смысл, поскольку обеспечивает порядок глобальной видимости, который актуален для многоядерных систем. Когда вы не можете быть уверены, что событие B всегда происходит после события A, вы просто не можете создать надежную логику, которая должна выполняться в многоядерных средах.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню