Я искал поточно-ориентированную реализацию счетчика, использующую Interlocked
, которая поддерживала увеличение на произвольные значения, и нашел этот образец прямо из Interlocked.Документация CompareExchange
(немного изменена для простоты):
private int totalValue = 0;
public int AddToTotal(int addend)
{
int initialValue, computedValue;
do
{
// How can we get away with not using a volatile read of totalValue here?
// Shouldn't we use CompareExchange(ref TotalValue, 0, 0)
// or Thread.VolatileRead
// or declare totalValue to be volatile?
initialValue = totalValue;
computedValue = initialValue + addend;
} while (initialValue != Interlocked.CompareExchange(
ref totalValue, computedValue, initialValue));
return computedValue;
}
public int Total
{
// This looks *really* dodgy too, but isn't
// the target of my question.
get { return totalValue; }
}
Я понимаю, что пытается сделать этот код, но я не уверен, как это может сойти с рук, если не использовать изменчивое чтение общей переменной при назначении временная переменная, добавляемая в.
Есть ли шанс, что initialValue
будет содержать устаревшее значение на протяжении всего цикла, из-за чего функция никогда не вернется? Или барьер памяти (?) В CompareExchange
исключает такую возможность? Любое понимание будет оценено.
РЕДАКТИРОВАТЬ : я должен пояснить, что я понимаю, что если CompareExchange
вызвал последующее чтение totalValue
, чтобы оно было актуальным по состоянию на последний вызов CompareExchange
, тогда этот код подойдет. Но это гарантировано?