2016-10-27 4 views
3

Wie bekannt std::shared_timed_mutex (C++ 14) und std::shared_mutex (C++ 17) einen Leistungsvorteil gegenüber std::mutexnur für eine sehr langestd::shared_lock s (liest-Operationen), und wenn mehr als std::shared_lock s std::unique_lock s.Gibt es einen Ansatz von Shared Mutex für eine kurze gemeinsame Operationen und einige eindeutige Operationen?

Aber auch wenn die meisten seiner Leseoperationen sind, und sie sind kurz, dann std::mutex schneller sein wird - das ist, warum in der C++ 11-Standard std::shared_mutex und std::shared_timed_mutex wurden sofort nicht enthalten.

Gibt es einen Ansatz oder Durchführung eine Art gemeinsamen Mutex, die einen Leistungsvorteil gegenüber std::mutex hat, auch für kurze Operationen, wenn der liest nicht nur mehr, und noch viel mehr, wie unten?

std::unique_lock/std::shared_lock = 1/1 000 000 000 000

Gibt es eine Annäherung der gemeinsamen Mutex für kurze Shared-Operationen und einige einzigartige Operationen?

+1

ive meine eigene einfache 'gemeinsame Spin-Lock' vor einer Weile geschrieben, vielleicht ist es schneller (IDK) https://github.com/domso/network/blob/master /network/rw_mutex.h https://github.com/domso/network/blob/master/src/rw_mutex.cpp – Domso

Antwort

0

ein möglicher Ansatz könnte die Verwendung von duplizierten Daten sein. Dies sollte sehr gut mit einer hohen Anzahl von Lesern und nur wenigen Autoren skalieren. Ich weiß nicht, ob seine schneller als shared_mutex(), sondern ist eine Alternative

Grundidee:

Jeder Leser arbeitet an einem Leser-Kopie, während ein Schriftsteller die seperate Schreiber-Kopie ändern. Um Änderungen zu übernehmen, speichern Sie das Writer-Objekt in einem neuen Reader-Objekt, das von jedem neuen Reader erfasst wird. Der nächste Commit würde in dem nun alten Reader-Objekt gespeichert werden. Daher muss der Schreiber warten, bis alle alten Leser ihre Sperre für dieses Objekt freigegeben haben.

einfaches Beispiel:

struct data{ 
    int a; 
}; 

struct secured_data { 
    data read[2]; 
    data write; 
    std::atomic<int> current = 0; 
    std::atomic<int> num_read[2] = 0; 

    std::mutex m; 

    data* read_lock() { 
     // increase reader-counter of current data-object 
     int c = current.load(); 
     num_read[c].fetch_add(1); 
     // return current copy 
     return &read + c; 
    } 

    void read_unlock(data* old) { 
     // decrease the old data-object (which was returned by read_lock()) 
     num_read[old - &read].fetch_sub(1); 


    } 

    data* lock() { 
     m.lock(); 
     // every modification happens on a seperate copy 
     write = read[current.load()]; 
     return &write; 
    } 

    void unlock() { 
     int c; 
     // wait until all readers using an old copy have released their lock 
     do { 
      c = current.load(); 
     } while (num_read[(c + 1) % 2].load() != 0); 
     // copy into new read-object 
     read[(c + 1) % 2] = write; 
     // swap read-object 
     // all readers now use an old version 
     current.store((c + 1) % 2); 
     m.unlock(); 
    } 
} 
+0

Thak Sie. Aber: 'num_read [c] .fetch_add (1);' ist Read-Modify-Write-Operation, die eine Cache-Zeile in Ping Pong abspielt, dh eXclusive-Zustand der Cache-Zeile, die 'num_read [c]' an jedes übertragen enthält CPU-Core für jedes 'read_lock()' oder 'read_unlock()' - es ist dasselbe, das im konventionellen 'std :: mutex' passiert und es kann nicht schneller sein als' std :: mutex'. Wenn es nur Leser (ohne Writer) gibt, kann shared-lock nur 'load (any barrier) 'und' store (std :: memory_order_release) 'verwenden, um schneller zu sein als' std :: mutex'. – Alex

Verwandte Themen