В настоящее время я работаю над классом 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
Около 44:35 разговоров об атомном оружии Херб упоминает, что могут возникнуть взаимоблокировки, не используя SC приобретать и отпускать. Я думаю, что он получает, что если у вас есть блокировка A, а код для захвата блокировки B переупорядочен перед разблокировкой A для одного потока, а другой поток имеет противоположную ситуацию, тогда потоки могут захватывать обе блокировки и пытаться захватить друг друга ", прежде чем освободить их. – JPark
Что такое "SC приобретать и выпускать"? –
Пример: Нить 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