2015-03-23 2 views
0

В настоящее время я работаю над классом SpinLock и пытаюсь сделать это как разумно, насколько это возможно, в основном, на основе рекомендаций здесь: https://software.intel.com/en-us/articles/implementing-scalable-atomic-locks-for-multi-core-intel-em64t-and-ia32-architecturesКак безопасно написать тестовый и тестовый набор (TATAS) спин-блокировки с C++ 11 для x86 (-64)?

Работа в прогрессе выглядит следующим образом:

class Spinlock 
{ 
public: 
    Spinlock() : m_lock(false) {} 

    void lock() 
    { 
     // heavy test here for the usual uncontested case 
     bool exp = false; 
     if (!m_lock.compare_exchange_weak(exp, true, std::memory_order_acquire)) 
     { 
      int failCount = 0; 
      for (;;) 
      { 
       // processor spin loop hint 
       _mm_pause(); 

       // spin on mov instead of lock instruction 
       if (!m_lock.load(std::memory_order_relaxed)) 
       { 
        // heavy test now that we suspect success 
        exp = false; 
        if (m_lock.compare_exchange_weak(exp, true, std::memory_order_acquire)) 
        { 
         return; 
        } 
       } 

       // backoff (potentially make exponential later) 
       if (++failCount == SOME_VALUE) 
       { 
        // Yield somehow. 
        failCount = 0; 
       } 
      } 
     } 
    } 

    void unlock() 
    { 
     m_lock.store(false, std::memory_order_release); 
    } 

    std::atomic_bool m_lock; 
}; 

Однако , похоже, что такое расслабленное чтение может теоретически разрешить сгенерированный код делать неожиданные вещи, такие как создание тупиков: http://joeduffyblog.com/2009/02/23/the-magical-dueling-deadlocking-spin-locks/

Этот код не должен запираться так же, как связанный пример, потому что внешний приобретатель должен сохранять расслабленный нагрузка от дрейфующих позади, но на самом деле я не справляюсь со всеми преобразованиями кода, которые могут существовать. Какие заказы памяти и/или заборы мне нужны, чтобы сохранить этот код без потери производительности? Возможно ли, чтобы реализация backoff происходила значительно более или менее часто (> несколько циклов), чем предполагалось, потому что упорядоченные заказы памяти слишком расслаблены?

Относительно примечания, почему примеры спин-блокировки по всему Интернету используют порядок памяти для освобождения памяти для последовательных последовательных последовательностей? Я нашел комментарий о том, что разрешение релиза SpinLock скрестить позже SpinLock приобретают может привести к проблемам: http://preshing.com/20120913/acquire-and-release-semantics/#IDComment721195810

ответ

0

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

Приобретение операции гарантирует, что последующие считывания не будут переупорядочены до операции получения как компилятором, так и ЦП.

Какие заказы памяти и/или ограждения необходимы для обеспечения безопасности этого кода без потери производительности?

Вам не нужна дополнительная синхронизация здесь, ваш код поступает правильно.

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

Поскольку семантики получения/выпуска достаточно для реализации мьютекса. На некоторых архитектурах последовательная последовательность операций более дорогая, чем покупка/выпуск.

Я не могу рекомендовать достаточно просмотра atomic<> Weapons: The C++ Memory Model and Modern Hardware, он охватывает эту тему очень подробно.

+0

Около 44:35 разговоров об атомном оружии Херб упоминает, что могут возникнуть взаимоблокировки, не используя SC приобретать и отпускать. Я думаю, что он получает, что если у вас есть блокировка A, а код для захвата блокировки B переупорядочен перед разблокировкой A для одного потока, а другой поток имеет противоположную ситуацию, тогда потоки могут захватывать обе блокировки и пытаться захватить друг друга ", прежде чем освободить их. – JPark

+0

Что такое "SC приобретать и выпускать"? –

+0

Пример: Нить 1 (как написано): Блокировка A, Разблокировка A, Блокировка B, Разблокировка B Резьба 2 (как написано): Блокировка B, Разблокировка B, Блокировка A, Разблокировка A Резьба 1 (нет-SC потенциал): Блокировка A, Блокировка B, Разблокировка A, Разблокировка B Резьба 2 (потенциал без SC): Блокировка B, Блокировка A, Разблокировка B, Разблокировка A Здесь, если A и B заблокированы одновременно, потоки будут застревать друг для друга. – JPark

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