Блокированный и изменчивый

У меня есть переменная, которую я использую для представления состояния. Он может быть прочитан и записан из нескольких потоков.

я использую Interlocked.Exchange а также Interlocked.CompareExchange изменить это. Однако я читаю это из нескольких потоков.

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

Однако, если я устанавливаю переменную на volatile, то генерируется предупреждение об использовании volatile и передаче с помощью ref методам Interlocked.

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

E сть Interlocked.Read но это для 64-битных типов и не доступно на компактной платформе. В документации сказано, что он не нужен для 32-битных типов, поскольку они уже выполняются за одну операцию.

В Интернете есть заявления о том, что вам не нужна изменчивость, если вы используете блокированные методы для всего вашего доступа. Однако вы не можете прочитать 32-битную переменную, используя методы Interlocked, поэтому вы не можете использовать методы Interlocked для всего вашего доступа.

Есть ли какой-нибудь способ выполнить потокобезопасное чтение и запись моей переменной без использования блокировки?

2 ответа

Решение

Вы можете смело игнорировать это предупреждение при использовании Interlocked.Xxx функции (см. этот вопрос), потому что они всегда делают изменчивые операции. Так что volatile Переменная отлично подходит для общего состояния. Если вы хотите во что бы то ни стало избавиться от предупреждения, вы можете выполнить блокировку чтения с помощью Interlocked.CompareExchange (ref counter, 0, 0),

Изменить: На самом деле вам нужно volatile в вашей переменной состояния, только если вы собираетесь писать в нее напрямую (т.е. не используя Interlocked.Xxx). Как упоминалось в jerryjvl, для чтения переменной, обновленной с помощью блокированной (или изменчивой) операции, будет использоваться самое последнее значение.

Блокированные операции и энергозависимые на самом деле не должны использоваться одновременно. Причина, по которой вы получаете предупреждение, заключается в том, что оно (почти?) Всегда указывает на то, что вы неправильно поняли, что делаете.

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

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

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

Другие вопросы по тегам