2014-12-09 3 views
3

Является ли следующий код безопасным (учитывая его изолированность) от рваного чтения?Атомная операция Защита резьбы - нужна ли мне «зеркальная» атомная прочесть?

private static double flopsErrorMargin = 0.01d; 

public static double FlopsErrorMargin { 
    get { 
     double result = flopsErrorMargin; 
     Thread.MemoryBarrier(); 
     return result; 
    } 
    set { 
     Interlocked.Exchange(ref flopsErrorMargin, value); 
    } 
} 

Операция записи атомного (Interlocked.Exchange()) требуется потому, что двойной не гарантируется быть записана в одной операции на платформе .NET (за исключением детали реализации на 64-разрядных средах).

Однако мне также нужна операция «зеркало» на стороне чтения? Например. я все еще рискую получить разорванное чтение, потому что я не читаю значение атомарно?

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

+2

Просто собираешься выбросить его там, что, как и в случае с очень многими другими проблемами с низким уровнем многопоточности, лучше всего написать код, который не должен иметь дело с этими типами вопросов. Вы действительно должны быть уверены, что потратить время на использование многоуровневой структуры более высокого уровня с довольно консервативной синхронизацией является просто неприемлемо медленным, прежде чем вы даже потрудитесь, чтобы задать * такой вопрос. – Servy

+0

В принципе это небезопасно, хотя на практике (по крайней мере, для x86) я никогда не смог воспроизвести разорванное чтение. См. [Этот ответ] (http://stackoverflow.com/questions/3679209/why-doesnt-this-code-demonstrate-the-non-atomicity-of-reads-writes/3679400#3679400) для получения дополнительной информации. Я был удивлен, увидев этот результат. Конечно, возможно, лучше не полагаться на поведение, которое не гарантируется. –

+0

@ DanBryant Конечно, стоит отметить, что если есть что-то вроде.00001% вероятность неудачи в вашем коде, есть довольно низкие шансы, что вы действительно узнаете, когда это произойдет. Программа должна быть очень большой и сложной, чтобы шансы на неудачу в создании достаточно, чтобы быть заметным, - это тот, в котором диагностика такой ошибки была бы очень сложной. – Servy

ответ

3

Нет, возможны разрывы. Предположим, что ваш доступ к полям считывает данные и чередуется частично с помощью Interlocked.Exchange, тогда другие 32 бита будут обновленным значением Exchange и, таким образом, производят разрывы чтения.

Для атомного чтения вам необходимо использовать Interlocked.Read (в 32-разрядных машинах).

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

что также означает, что рваные значения возможны.

Вы можете определить свой собственный атомный Read для double следующим

public static double Read(ref double location) 
{ 
    return Interlocked.CompareExchange(ref location, 0d, 0d); 
} 

Это как Interlocked.Read(long) реализуется внутри.

+1

Interlocked.Read не поддерживает двойной, однако; это только для длинных (Int64) переменных. –

+0

@ DanBryant Хотя это правда, точка остается такой же. Читает больше, чем размер слова не является атомарным. Вам нужна синхронизация. –

+1

@DanBryant Обновлено сообщение, чтобы показать, как реализовать 'Interlocked.Read' для' double'. –

2

Я все еще рискую получить разорванное чтение, потому что я не читаю значение атомарно?

Да. Возвращаемое значение Interlocked.Exchange не будет разорвано, а значение, которое flopsErrorMarginв конечном итоге заканчивается как будет value (это две гарантии, которые дает Interlocked.Exchange), но несинхронизированный доступ для чтения может быть разорван.

Смежные вопросы