Реализуйте высокопроизводительный мьютекс, похожий на мьютекс Qt

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

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

В настоящее время я использовал Qt QMutex для этой задачи, и он работает хорошо: мьютекс имеет незначительные накладные расходы.

Однако я должен перенести его только на c ++ 11 / STL. При использовании std :: mutex производительность падает на 66%, и потоки проводят большую часть своего времени, блокируя мьютекс.

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

Я хотел бы реализовать это в STL. Есть ли простой способ, основанный на std :: atomic и std :: mutex? Я копался в коде Qt, но он кажется слишком сложным для моего использования (мне не нужны тайм-ауты блокировок, pimpl, небольшой размер и т. Д.).

Изменить: я пробовал спинлок, но это не работает, потому что:

Периодически (каждые несколько секунд) другой поток блокирует мьютексы и очищает буфер. Это занимает некоторое время, поэтому все рабочие потоки блокируются в это время. Спин-блокировки делают расписание занятым, в результате чего сброс будет в 10-100 раз медленнее, чем с надлежащим мьютексом. Это не приемлемо

Изменить: я пробовал это, но это не работает (блокирует все темы)

class Mutex
{
public:
    Mutex() : lockCounter(0) { }

    void lock()
    {
        if(lockCounter.fetch_add(1, std::memory_order_acquire)>0)
        {
            std::unique_lock<std::mutex> lock(internalMutex);
            cv.wait(lock);
        }
    }

    void unlock();
    {
        if(lockCounter.fetch_sub(1, std::memory_order_release)>1)
        {
            cv.notify_one();
        }
    }


private:
    std::atomic<int> lockCounter;
    std::mutex internalMutex;
    std::condition_variable cv;
};

Спасибо!

Изменить: окончательное решение

Быстрый мьютекс MikeMB работал довольно хорошо.

В качестве окончательного решения я сделал:

Используйте простую спин-блокировку с try_lockКогда поток не может выполнить try_lock, вместо ожидания он заполняет очередь (которая не используется другими потоками) и продолжаетКогда поток получает блокировку, он обновляет буфер с текущим результатом, но также с результатами, сохраненными в очереди (он обрабатывает свою очередь)Промывка буфера была сделана намного эффективнее: блокирующая часть меняет только два указателя.

Ответы на вопрос(2)

Ваш ответ на вопрос