Вопрос

Допустим, у меня есть структура, состоящая из 100 байт.Какие гарантии я получаю в отношении следующего кода?

m_myLargeStruct = someValue; // copying 100 bytes
Thread.MemoryBarrier();

// Executed by another thread, after "Thread.MemoryBarrier" was called by the first thread
Console.WriteLine(m_myLargeStruct.ToString());

Гарантирует ли модель памяти, что копия в 100 байт будет завершена после установки барьера памяти?или барьеры памяти применяются только для типов, размер которых соответствует архитектуре процессора?(4 байта для 32-битных и 8 байт для 64-битных).
Является ли это причиной, по которой изменчивый ключевое слово применимо только к примитивным типам?(если я объявлю 8-байтовый элемент как volatile, это означает, что для изменения его значения будет использоваться заблокированный instrinct?[поскольку атомарность не гарантируется для типов размером более 4 байт на 32-битных машинах]).

Надеюсь, я выразился достаточно ясно..:)
Спасибо

Это было полезно?

Решение

Очевидно, что ответ таков НЕТ, или, скорее, у вас нет никаких гарантий ни в чем.Ничто не мешает операционной системе заменить поток, который выполняет запись в 100-байтовую структуру, перед запуском потока, который выводит 100-байтовую структуру.

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

Другие советы

Если только поток чтения тоже не имеет барьера памяти, я не подумай это вам очень поможет.

Лично я бы уклонился от:

  • Структуры, которые настолько велики
  • Глубокое проникновение в модель памяти для написания кода без блокировок

...если только у вас нет действительно важной причины для этого.Это чрезвычайно трудно получить правильное кодирование без блокировок с изменяемыми данными;Я считаю, что даже эксперты борются с этим.Обычно я нахожу, что подход "снимать блокировку для каждого блока, обращающегося к данным" проще реализовать правильно и хорош с точки зрения производительности в 99% случаев.

Я доверяю команде PFX в Microsoft в правильном написании кода без блокировок, и чтобы они предоставили мне способы, которыми я могу относительно легко использовать их код для написания своих собственных программ без блокировок.Я не доверяю себе, что смогу правильно разобраться в подобных вещах.Если мне когда-нибудь понадобится явно использовать барьер памяти, это, вероятно, означает, что я слишком стараюсь.

Вам нужен еще один барьер памяти во втором потоке, перед WriteLine .(Если ваша система предоставляет асимметричные барьеры памяти, достаточно выполнить барьер освобождения после назначения и барьер получения перед линией записи).

Размер данных не имеет значения.

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

В частности, потоку записи необходим барьер памяти 'release', а потоку чтения необходим барьер памяти 'acquire' (если базовая платформа поддерживает семантику отдельного барьера).

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top