2016-06-13 11 views
3

Interlocked.Read(ref long) «оптимизирован» на 64-битных архитектурах? То есть если я пишу библиотеку, которая может использоваться обеими архитектурами, следует ли мне беспокоиться о влиянии на производительность использования Interlocked.Read без необходимости на 64-битных процессорах?Interlocked.Read/Exchange для longs на 64-битных архитектурах

Я думал об использовании что-то вроде этого, так что мне интересно, если это имеет смысл:

// X64 is a preprocessor constant set for x64 builds 

    [MethodImpl(MethodImplOptions.AggressiveInlining)] 
    public static long Read(ref long address) 
    { 
#if X64 
     // atomic on 64-bit processors 
     return address; 
#else 
     // if I got it right, this creates a full memory barrier 
     return Interlocked.Read(ref address); 
#endif 
    } 

    [MethodImpl(MethodImplOptions.AggressiveInlining)] 
    public static void Write(ref long address, long value) 
    { 
#if X64 
     // atomic on 64-bit processors 
     address = value; 
#else 
     // if I got it right, this creates a full memory barrier 
     Interlocked.Exchange(ref address, value); 
#endif 
    } 
+0

Вы не должны беспокоиться о «влиянии производительности на использование« Interlocked.Read » –

+0

@Henk: Я думал, что это« не оптимизировать слишком рано », а не« не оптимизировать когда-либо, период ». Если несколько потоков используют этот код одновременно, я не вижу необходимости иметь полный барьер для каждого доступа. Кроме того, количество ПК с 32-разрядными процессорами уже достаточно низкое и будет только ниже. – Lou

+2

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

ответ

4

Да, вы обеспокоены тем, ненужны воздействия производительности Interlocked, потому что Interlocked не просто выполнить элементарное действие на ценностях, но и гарантирует, что значение виден для всех потоков (последовательная непротиворечивость). Позволь мне объяснить. На некоторых архитектурах (включая 64-разрядные архитектуры) значение, записанное в ячейку памяти, может кэшироваться для повышения производительности. Простое чтение значения может не читать «последнее» значение, написанное другим потоком, несмотря на то, что оно является атомной операцией. Interlocked также выполняет забор памяти, так что любые операции до ограждения имеют любые кешированные значения, сброшенные в фактическую память. Итак, хотя вы можете улучшить производительность незначительной суммы, вы также вводите потенциальные условия гонки. На архитектурах, где это не проблема, Interlocked не выполнит дополнительную работу и не сделает оптимизацию для вас.

К сожалению, документация для Interlocked: еще не совсем соответствует номиналу. См. http://www.albahari.com/threading/part4.aspx для получения более подробной информации о заборе, связанной с операциями Interlocked.

0

Я могу ответить только на второй вопрос - вы не должны быть связаны с ним. Все, что вы можете сделать, это определить, должны ли чтения и записи переменной быть потокобезопасными, а также соответствующим кодом. C# - абстракция - вы пишете язык, а не процессор. Компилятор и платформа .NET беспокоятся о процессоре.

64-разрядные считывания гарантированно будут атомарными на 64-разрядных процессорах, но, как вы сказали, вы пишете для обеих архитектур. Если стоимость блокировки является существенным препятствием, которое можно избежать в 64-битной архитектуре, это препятствие будет нерешенной проблемой для 32-разрядной архитектуры.

Существует стоимость, связанная с блокировкой, но большая стоимость будет связана с непредсказуемым поведением, которое исходит из не кодирования безопасности потоков.