it-swarm.com.de

Wie kann ich etwas wie std :: vector <std :: mutex> verwenden?

Ich habe eine große, aber möglicherweise unterschiedliche Anzahl von Objekten, in die gleichzeitig geschrieben wird. Ich möchte diesen Zugang mit Mutexen schützen. Zu diesem Zweck dachte ich, ich verwende einen std::vector<std::mutex>, aber das funktioniert nicht, da std::mutex keinen Konstruktor zum Kopieren oder Verschieben hat, während std::vector::resize() dies erfordert.

Was ist die empfohlene Lösung für dieses Rätsel?

edit : Benötigen alle C++ - Container mit wahlfreiem Zugriff Konstruktoren zum Ändern der Größe zum Kopieren oder Verschieben? Würde std :: deque helfen?

erneut bearbeiten

Zunächst einmal vielen Dank für all Ihre Gedanken. Ich bin nicht an Lösungen interessiert, die Mutizen vermeiden und/oder in die Objekte verschieben (ich gebe keine Details/Gründe an). Angesichts des Problems, dass ich eine einstellbare Anzahl von Mutices haben möchte (wobei die Anpassung garantiert erfolgt, wenn kein Mutex gesperrt ist), scheint es mehrere Lösungen zu geben.

1 Ich könnte eine feste Anzahl von Mutizen verwenden und eine Hash-Funktion verwenden, um Objekte Mutizen zuzuordnen (wie in der Antwort von Captain Oblivous). Dies führt zu Kollisionen, aber die Anzahl der Kollisionen sollte gering sein, wenn die Anzahl der Mutizen viel größer als die Anzahl der Threads, aber immer noch kleiner als die Anzahl der Objekte ist.

2 Ich könnte eine Wrapper-Klasse definieren (wie in der Antwort von ComicSansMS), z.

struct mutex_wrapper : std::mutex
{
  mutex_wrapper() = default;
  mutex_wrapper(mutex_wrapper const&) noexcept : std::mutex() {}
  bool operator==(mutex_wrapper const&other) noexcept { return this==&other; }
};

und benutze einen std::vector<mutex_wrapper>.

3 Ich könnte std::unique_ptr<std::mutex> verwenden, um einzelne Mutexe zu verwalten (wie in Matthias 'Antwort). Das Problem bei diesem Ansatz ist, dass jeder Mutex auf dem Heap einzeln zugewiesen und freigegeben wird. Deshalb bevorzuge ich

4 std::unique_ptr<std::mutex[]> mutices( new std::mutex[n_mutex] );

wenn eine bestimmte Anzahl n_mutex von Mutices zugewiesen wird. Sollte diese Nummer später nicht ausreichen, finde ich einfach

if(need_mutex > n_mutex) {
  mutices.reset( new std::mutex[need_mutex] );
  n_mutex = need_mutex;
}

Welches von diesen (1,2,4) soll ich verwenden?

23
Walter

vector erfordert, dass die Werte beweglich sind, um ein zusammenhängendes Array von Werten beizubehalten, wenn es wächst. Sie könnten einen Vektor erstellen, der Mutexe enthält, aber Sie konnten nichts tun, um die Größe zu ändern.

Andere Behälter haben diese Anforderung nicht; Entweder deque oder [forward_]list sollte funktionieren, solange Sie die Mutexe entweder während der Konstruktion oder mithilfe von emplace() oder resize() erstellen. Funktionen wie insert() und Push_back() funktionieren nicht.

Alternativ können Sie eine zusätzliche Indirektionsstufe hinzufügen und unique_ptr speichern. Ihr Kommentar in einer anderen Antwort weist jedoch darauf hin, dass Sie die Mehrkosten einer dynamischen Zuweisung für inakzeptabel halten.

11
Mike Seymour

Sie könnten std::unique_ptr<std::mutex> anstelle von std::mutex verwenden. unique_ptrs sind beweglich.

11

Wenn Sie eine bestimmte Länge erstellen möchten:

std::vector<std::mutex> mutexes;
...
size_t count = 4;
std::vector<std::mutex> list(count);

mutexes.swap(list);
7
Awwit

Ich empfehle einen festen Mutex-Pool. Behalten Sie ein festes Array von std::mutex bei, und wählen Sie das zu sperrende Array anhand der Adresse des Objekts aus, wie Sie es bei einer Hashtabelle tun könnten.

std::array<std::mutex, 32> mutexes;

std::mutex &m = mutexes[hashof(objectPtr) % mutexes.size()];

m.lock();

Die hashof-Funktion könnte etwas einfaches sein, das den Zeigerwert um einige Bits verschiebt. Auf diese Weise müssen Sie die Mutexe nur einmal initialisieren und vermeiden, dass die Größe des Vektors geändert wird.

3

Wenn Effizienz ein solches Problem ist, gehe ich davon aus, dass Sie nur sehr kleine Datenstrukturen haben, die sehr oft geändert werden. Dann ist es wahrscheinlich besser, Atomic Compare And Swap (und andere atomare Operationen) anstelle von Mutexen zu verwenden, insbesondere std::atomic_compare_exchange_strong

2
schoppenhauer

Wie wäre es, jeden Mutex als Zeiger zu deklarieren?

std::vector<std::mutex *> my_mutexes(10)
//Initialize mutexes
for(int i=0;i<10;++i) my_mutexes[i] = new std::mutex();

//Release mutexes
for(int i=0;i<10;++i) delete my_mutexes[i];
0
user506146