Чтение двойного не потокобезопасно? - PullRequest
15 голосов
/ 09 сентября 2010

Обновление : Я только что наткнулся на это в Ответ Эрика Липперта на другой вопрос (он цитирует спецификацию):

Чтение и запись других типов, в том числе длинный, удлиненный, двойной и десятичный, а также определяемый пользователем типы, не гарантируется атомарный.

ОК, поэтому чтение double является , а не атомарным. Это означает, что значение может измениться в середине чтения, верно? Так как же можно атомарно прочитать значение double?


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

Но для double значений Interlocked.Read нет, хотя System.Double является 64-битным значением.

Я вижу странное поведение в моей программе, когда мой графический интерфейс, который отображает double в текстовом поле, в то время как double также часто обновляется другими потоками, показывает правильное значение (вблизи 200,0) большинство времени, а затем случайным образом показывает ошибочное значение (например, -0,08) иногда .

Может быть, это проблема с потоками, или, может быть, это что-то еще. Но сначала я хотел сузить возможности. Итак: чтение double потокобезопасно?

Ответы [ 4 ]

17 голосов
/ 09 сентября 2010

читает двойной потокобезопасный?

Нет.Как сказано в спецификации,

Чтение и запись других типов, включая long, ulong, double и decimal, а также определяемые пользователем типы, не гарантированно являются атомарными.

Продолжаем.

Это означает, что значение может быть изменено в середине чтения, верно?

Да.

Итак, как можно атомарно прочитать двойное значение?

Вы блокируете каждый доступ к изменяемымпеременная.

И вопрос, который вы не задавали, но часто задают в качестве продолжения ваших вопросов:

Делает ли поле "volatile" создание чтения / записиэто атомно?

Нет.Недопустимо создавать изменчивое поле типа double.

9 голосов
/ 09 сентября 2010

Обычный способ: контроль доступа с помощью замка.

6 голосов
/ 11 января 2013

Используйте Interlocked.Exchange ИЛИ Interlocked.CompareExchange для атомарного чтения следующим образом.

Interlocked.Exchange(ref somevariable, somevariable)

Возвращает исходное значение.

Если вы хотите избежать написания, используйте compareExchange.

Interlocked.CompareExchange(ref somevariable, somevalue, somevalue);

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

2 голосов
/ 09 сентября 2010

CLR обещает только переменное выравнивание 4. Это означает, что вполне возможно, что long или double изменят границы строки кэша CPU. Это делает чтение гарантированно неатомарным.

Это также довольно серьезная проблема перфорирования: чтение такой плохо выровненной переменной происходит в 3 раза медленнее. Ничего не поделаешь, кроме хакерских указателей.

...