Implementar um mutex de alto desempenho semelhante ao do Qt

Eu tenho um aplicativo científico multi-thread em que vários threads de computação (um por núcleo) precisam armazenar seus resultados em um buffer comum. Isso requer um mecanismo mutex.

Os threads de trabalho gastam apenas uma pequena fração do tempo gravando no buffer, portanto, o mutex é desbloqueado a maior parte do tempo, e os bloqueios têm uma alta probabilidade de êxito imediatamente, sem esperar que outro thread seja desbloqueado.

Atualmente, usei o QMutex do Qt para a tarefa e funciona bem: o mutex tem uma sobrecarga insignificante.

No entanto, eu tenho que portá-lo para c ++ 11 / STL apenas. Ao usar std :: mutex, o desempenho cai em 66% e os threads passam a maior parte do tempo bloqueando o mutex.

Depois de outra pergunta, percebi que o Qt usa um mecanismo de bloqueio rápido baseado em uma bandeira atômica simples, otimizada para casos em que o mutex ainda não está bloqueado. E volta a um mutex do sistema quando ocorre o bloqueio simultâneo.

Eu gostaria de implementar isso no STL. Existe uma maneira simples com base em std :: atomic e std :: mutex? Eu cavei no código do Qt, mas parece muito complicado para o meu uso (não preciso de tempos limite de bloqueios, pimpl, tamanho reduzido, etc ...).

Edit: Eu tentei um spinlock, mas isso não funciona bem porque:

Periodicamente (a cada poucos segundos), outro encadeamento bloqueia os mutexes e libera o buffer. Isso leva algum tempo, para que todos os threads de trabalho sejam bloqueados no momento. Os spinlocks tornam a programação ocupada, fazendo com que o fluxo seja 10-100x mais lento do que com um mutex adequado. Isto não é aceitável

Edit: Eu tentei isso, mas não está funcionando (bloqueia todos os threads)

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;
};

Obrigado!

Edit: Solução final

O mutex rápido do MikeMB estava funcionando muito bem.

Como solução final, fiz:

Use um spinlock simples com um try_lockQuando um encadeamento falha em try_lock, em vez de esperar, ele preenche uma fila (que não é compartilhada com outros encadeamentos) e continuaQuando um encadeamento obtém um bloqueio, ele atualiza o buffer com o resultado atual, mas também com os resultados armazenados na fila (processa sua fila)A descarga do buffer foi feita com muito mais eficiência: a parte de bloqueio apenas troca dois ponteiros.

questionAnswers(2)

yourAnswerToTheQuestion