Где InterlockedRead?
Win32 api имеет набор функций InterlockedXXX для атомарного и синхронного управления простыми переменными, однако, как представляется, нет функции InterlockedRead, чтобы просто получить значение переменной. Почему?
MSDN говорит, что "простые чтения и записи в правильно выровненные 32-битные переменные являются атомарными операциями", но добавляет, что "Однако доступ не гарантируется для синхронизации", что означает, как я понимаю, что простой операция чтения переменной может иметь место, а другая, скажем, операция InterlockedAdd. Итак, почему нет функции блокировки для чтения переменной?
Я думаю, что значение можно прочитать как результат InterlockedAdd-ing zero, но это не похоже на правильный путь.
Ответы
Ответ 1
Обычным способом реализации этого является использование операции сравнения (например, InterlockedCompareExchange64
), где оба значения одинаковы. У меня есть подозрительное подозрение, что это может быть сделано более эффективно, чем добавление 0 по какой-то причине, но у меня нет никаких доказательств, чтобы поддержать это.
Интересно, что .NET Interlocked
класс не получил Read
до .NET 2.0. Я считаю, что Interlocked.Read
реализуется с помощью Interlocked.CompareExchange
. (Обратите внимание, что документация для Interlocked.Read
поражает меня как несколько вводящую в заблуждение - она говорит об атомарности, но не волатильности, что означает что-то очень специфичное для .NET. Я не уверен, что модель памяти Win32 гарантирует видимость новых записанных значений из другого потока, если что угодно.)
Ответ 2
Я думаю, что ваша интерпретация "не синхронизирована" неверна. Простые чтения являются атомарными, но вы должны сами заботиться о переупорядочении и проблемах с памятью. Первый обрабатывается с помощью инструкций по заборам в соответствующих местах, последний не является проблемой с чтением (но потенциальная одновременная запись должна обеспечивать надлежащую видимость, которую должны выполнять функции блокировки, если они соответствуют инструкциям ASM LOCKED).
Ответ 3
Суть всего этого обсуждения - правильное выравнивание, которое выделено в разделе я ххх в разделе "12.6.2 Alignment
":
Built-in datatypes shall be properly aligned, which is defined as follows:
• 1-byte, 2-byte, and 4-byte data is properly aligned when it is stored at
a 1-byte, 2-byte, or 4-byte boundary, respectively.
• 8-byte data is properly aligned when it is stored on the same boundary
required by the underlying hardware for atomic access to a native int.
В принципе, все 32-битные значения имеют требуемое выравнивание, а на 64-битной платформе 64-битные значения также имеют требуемое выравнивание.
Обратите внимание: атрибуты явно меняют расположение классов в памяти, что может привести к потере этого выравнивания. Это атрибуты, специально предназначенные для этой цели, но, если вы не изменили макет, это не должно относиться к вам.
С этой целью цель класса Interlocked
заключается в предоставлении операций, которые (перефразировать) можно наблюдать только в состоянии "до" или "после". Операции с блокировкой обычно вызывают озабоченность при изменении памяти (как правило, с помощью некоторого нетривиального способа сравнения). Поскольку найденная вами статья MSDN указывает, операции чтения (при правильной выровненности) могут считаться атомарными в любое время без дополнительных мер предосторожности.
Существуют и другие соображения при работе с операциями чтения:
- На современных процессорах, хотя чтение может быть атомарным, оно также может возвращать неправильное значение из старого кэша где-то... вот где вам может понадобиться сделать поле "volatile", чтобы получить ожидаемое поведение
- Если вы имеете дело с 64-битным значением на 32-разрядном оборудовании, вам может потребоваться использовать операцию
Interlocked.Read
, чтобы гарантировать, что все 64-битное значение считывается в одной атомной операции (иначе это может быть выполнено как 2 отдельных 32-битных чтения, которые могут быть с обеих сторон обновления памяти).
- Переупорядочение ваших чтений/записей может привести к тому, что вы не получите ожидаемое значение; в этом случае может потребоваться некоторый барьер памяти (явный или с помощью операций класса
Interlocked
)
Краткое описание; насколько атомарность идет, очень вероятно, что то, что вы делаете, не нуждается в какой-либо специальной инструкции для чтения... может быть, есть другие вещи, которые вам нужно соблюдать, в зависимости от того, что именно вы делаете.