Подтвердить что ты не робот

Летучие против VolatileRead/Write?

Я не могу найти ни одного примера VolatileRead/write (try...), но все же:

Когда следует использовать volatile vs VolatileRead?

AFAIK вся цель volatile заключается в создании половинных заборов, поэтому:

  • Для операции READ чтение/запись (по другим темам), которая появляется ПОСЛЕ текущей операции, не будет проходить перед ограждением. следовательно, мы читаем последнее значение.

Вопрос № 1

Итак, для чего мне нужен VolatileRead? кажется, что volatile уже выполняет свою работу.

Плюс - в С# все записи являются volatile (в отличие от Java), независимо от того, пишете ли вы в volatile или в энергонезависимом поле - и поэтому я спрашиваю: почему я нужен volatileWrite?

Вопрос № 2

Это реализация для VolatileRead:

[MethodImpl(MethodImplOptions.NoInlining)]
public static int VolatileRead(ref int address)
{
    int num = address;
    MemoryBarrier();
    return num;
}

Почему существует строка int num = address;? они уже имеют аргумент адреса, который явно удерживает значение.

4b9b3361

Ответ 1

Вы никогда не должны использовать Thread.VolatileRead/Write(). Это была ошибка проектирования в .NET 1.1, она использует полный барьер памяти. Это было исправлено в .NET 2.0, но они больше не могли исправить эти методы и должны были добавить новый способ сделать это, предоставляемый классом System.Threading.Volatile. Это класс, о котором знает дрожание, он заменяет методы в jit время версией, подходящей для конкретного типа процессора.

Комментарии в исходном коде для класса Volatile, доступного через ссылочный источник, сообщают сказке (отредактировано для соответствия):

// Methods for accessing memory with volatile semantics.  These are preferred over 
// Thread.VolatileRead and Thread.VolatileWrite, as these are implemented more
// efficiently.
//
// (We cannot change the implementations of Thread.VolatileRead/VolatileWrite 
// without breaking code that relies on their overly-strong ordering guarantees.)
//
// The actual implementations of these methods are typically supplied by the VM at 
// JIT-time, because C# does not allow us to express a volatile read/write from/to 
// a byref arg. See getILIntrinsicImplementationForVolatile() in jitinterface.cpp.

И да, у вас возникнут проблемы с поиском примеров его использования. Справочный источник - отличное руководство с мегабайтами тщательно написанного, проверенного и сраженного шрамов кода С#, который занимается потоковой обработкой. Количество раз, когда оно использует VolatileRead/Write: ноль.

Честно говоря, модели памяти .NET - это беспорядок с противоречивыми предположениями, сделанными CLR mm и С# mm, с новыми правилами, добавленными для ядер ARM совсем недавно. Некоторое доказательство этого имеет семантика weirdo ключевого слова volatile, что означает разные вещи для разных архитектур. Хотя для процессора со слабой моделью памяти обычно можно предположить, что то, что говорит спецификация языка С#, является точной.

Заметьте, что Джо Даффи отказался от всей надежды и просто отлаживает все его использование. В целом очень неразумно предполагать, что вы можете сделать лучше, чем примитивы, предоставляемые языком и каркасом. Раздел "Примечания" класса "Летучий" возвращает точку дома:

При нормальных обстоятельствах оператор блокировки С#, оператор Visual Basic SyncLock и класс Monitor обеспечивают самый простой и наименее подверженный ошибкам способ синхронизации доступа к данным, а класс Lazy обеспечивает простой способ записи ленивого кода инициализации без прямого использования блокировки с двойной проверкой.

Ответ 2

Если вам нужен более мелкозернистый контроль над тем, как ограждения применяются к коду, вы можете использовать static Thread.VolatileRead или Thread.VolatileWrite.

Объявление переменной volatile означает, что компилятор не кэширует его значение и всегда считывает значение поля, а когда выполняется запись, компилятор немедленно записывает назначенные значения.

Два метода Thread.VolatileRead и Thread.VolatileWrite дают вам возможность иметь более мелкие зернистые без объявления переменной как изменчивой, так как вы можете решить, когда выполняете волатильную операцию чтения и когда волатильная запись, не имея привязки к чтению без кэширования и записи сразу, когда вы объявляете variale volatile, поэтому в бедных словах вы имеют больше контроля и больше свободы...

VolatileRead() читает последнюю версию адреса памяти, а VolatileWrite() записывает на адрес, делая адрес доступным для всех потоков. Использование последовательностей VolatileRead() и VolatileWrite() последовательно для переменной имеет тот же эффект, что и ее изменчивость.

Взгляните на этот пост в блоге, который объясняет на примере разницу...

Почему строка int num = address; здесь? у них уже есть адрес, который явно удерживает значение.

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

Примечания

Поскольку в Visual Basic ключевое слово volatile не существует, у вас есть единственный выбор для использования последовательно VolatileRead() и VolatileWrite() статических методов для достижения такого же эффекта ключевого слова volatile в С#.

Ответ 3

Почему строка int num = address; здесь? у них уже есть адрес, который явно удерживает значение.

address не является int. Это int* (так что это действительно адрес). Код разыменовывает указатель и копирует его на локальный, так что барьер возникает после разыменования.

Ответ 4

Чтобы подробнее объяснить ответ на алерут.

Volatile.Read и Volatile.Write такие же, как и изменчивый модификатор, как аргумент Royi Namir. Но вы можете использовать их с умом.

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

Подумайте о сценарии, в котором у вас есть личная переменная singleton, объявлена ​​как volatile и возвращается в свойство getter, как только она инициализируется, вам не нужно читать ее root из CPU Register, поэтому вы можете использовать Volatile.Read/Write, пока не будет созданный экземпляр, после создания все операции чтения могут выполняться как нормальное поле, иначе это будет большой успех.

В то время как вы можете использовать Volatile.Read или Volatile.Write по базе запросов. Лучшее использование - объявить поле без изменчивого модификатора и использовать Volatile.Read или Volatile.Write при необходимости.