Implementiere einen Hochleistungs-Mutex ähnlich dem von Qt

Ich habe eine wissenschaftliche Multithread-Anwendung, bei der mehrere Computerthreads (einer pro Kern) ihre Ergebnisse in einem gemeinsamen Puffer speichern müssen. Dies erfordert einen Mutex-Mechanismus.

Arbeits-Threads verbringen nur einen kleinen Teil ihrer Zeit mit dem Schreiben in den Puffer, sodass der Mutex die meiste Zeit entsperrt ist und Sperren mit hoher Wahrscheinlichkeit sofort erfolgreich sind, ohne auf das Entsperren eines anderen Threads zu warten.

Derzeit habe ich Qt's QMutex für die Aufgabe verwendet, und es funktioniert gut: Der Aufwand für den Mutex ist vernachlässigbar.

Ich muss es jedoch nur nach c ++ 11 / STL portieren. Bei Verwendung von std :: mutex sinkt die Leistung um 66% und die Threads verbringen die meiste Zeit damit, den Mutex zu sperren.

Nach einer weiteren Frage stellte ich fest, dass Qt einen schnellen Sperrmechanismus basierend auf einem einfachen atomaren Flag verwendet, der für Fälle optimiert ist, in denen der Mutex noch nicht gesperrt ist. Und greift bei gleichzeitigem Sperren auf einen System-Mutex zurück.

Ich möchte dies in AWL implementieren. Gibt es einen einfachen Weg, der auf std :: atomic und std :: mutex basiert? Ich habe in Qts Code gebuddelt, aber er scheint für meine Verwendung zu kompliziert zu sein (ich benötige keine Sperren, Timeouts, Pickel, kleine Stellfläche usw.).

Bearbeiten: Ich habe versucht, ein Spinlock, aber das funktioniert nicht gut, weil:

Periodisch (alle paar Sekunden) sperrt ein anderer Thread die Mutexe und leert den Puffer. Dies dauert einige Zeit, sodass alle Worker-Threads zu diesem Zeitpunkt blockiert werden. Die Spinlocks beschäftigen die Planung und bewirken, dass der Flush 10-100x langsamer ist als bei einem richtigen Mutex. Das ist nicht akzeptabe

Bearbeiten: Ich habe es versucht, aber es funktioniert nicht (sperrt alle 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;
};

Vielen Dank

Bearbeiten: Endgültige Lösung

MikeMBs schneller Mutex funktionierte ziemlich gut.

ls endgültige Lösung habe ic

Verwende einen einfachen Spinlock mit einem try_lockWenn ein Thread nicht try_lock kann, füllen sie statt zu warten eine Warteschlange (die nicht mit anderen Threads geteilt wird) und fahren fortWenn ein Thread eine Sperre erhält, aktualisiert er den Puffer mit dem aktuellen Ergebnis, aber auch mit den in der Warteschlange gespeicherten Ergebnissen (es verarbeitet seine Warteschlange)Die Pufferspülung wurde wesentlich effizienter durchgeführt: Der blockierende Teil tauscht nur zwei Zeiger aus.

Antworten auf die Frage(4)

Ihre Antwort auf die Frage