2010-04-19 4 views
6

Angenommen, ich habe eine Thread-sichere Sammlung von Things (nennen Sie es eine ThingList), und ich möchte die folgende Funktion hinzufügen.Zurückgeben von Zeigern in einer thread-sicheren Weise

Thing * ThingList::findByName(string name) 
{ 
    return &item[name]; // or something similar.. 
} 

Aber auf diese Weise habe ich die Verantwortung für die Thread-Sicherheit an den anrufenden Code delegiert, die so etwas tun hätte:

try 
{ 
    list.lock(); // NEEDED FOR THREAD SAFETY 
    Thing *foo = list.findByName("wibble"); 
    foo->Bar = 123; 
    list.unlock(); 
} 
catch (...) 
{ 
    list.unlock(); 
    throw; 
} 

Offensichtlich ein RAII Sperren/Entsperren Objekt würde vereinfachen/entfernen Sie das try/catch/entsperrt, aber es ist immer noch einfach für den Anrufer zu vergessen.

Es gibt ein paar Alternativen, die ich angeschaut habe:

  • Return Thing von Wert, anstelle eines Zeiger - fein, es sei denn Sie müssen modifizieren, um die Sache
  • hinzufügen Funktion ThingList::setItemBar(string name, int value) - fein, aber diese neigen dazu, proliferieren
  • Zurückgeben eines zeigerartigen Objekts, das die Liste bei der Erstellung gesperrt und entsperrt es wieder bei der Zerstörung. Nicht sicher, ob dies eine gute/schlechte Übung ist ...

Was ist der richtige Ansatz dafür?

Antwort

4

Es gibt keinen "richtigen Ansatz"; Es hängt von den Bedürfnissen Ihrer Anwendung ab.

Wenn möglich, die Dinge nach Wert zurückgeben, oder eine Kopie zurückgeben, die der Anrufer tun kann, was auch immer sie wollen.

Eine Variante des Obigen besteht darin, eine änderbare Kopie zurückzugeben und dann eine Möglichkeit zur Verfügung zu stellen, ein modifiziertes Objekt in die Liste einzufügen. So etwas wie:

Dies kann jedoch Probleme verursachen, wenn mehrere Threads versuchen, das gleiche Objekt zu aktualisieren.

Die "pointerähnliche Objekt" Idee klingt cool, aber ich vermute, es würde zu schwer zu findenden Bugs führen, wenn irgendwo keine Locks freigegeben werden.

Ich würde versuchen, alle sperren/entsperren Code innerhalb ThingList, so dass die ThingList::set... Funktionen sind wahrscheinlich, was ich tun würde.

+0

Die „merge“ ist schön, aber es gibt eine versteckte Annahme, dass Ding Objekte wissen, wie man sich in der Liste finden. Du könntest auch einen "Schlüssel" zum Zusammenführen übergeben, aber dann hast du das Problem, ein gelöschtes Element zusammenzuführen ... – Roddy

3

speichern und zurück boost :: shared_ptr s

Sie haben während der Zugang zu sperren, aber sie sind sicher nach dem Entsperren

+1

boost :: shared_ptr tut nichts, um die Thread-Sicherheit der Sammlung zu schützen. –

+0

Es hängt genau davon ab, mit welchem ​​Thread-Sicherheitsproblem Sie umgehen möchten. Sie müssen sperren, wenn Sie auf die Sammlung zugreifen (lesen oder schreiben), aber Sie müssen das trotzdem tun. Durch das Zurückgeben eines gemeinsamen PTR garantieren Sie zumindest, dass, wenn die Sammlung hinter Ihnen geändert wird, Sie immer noch OK sind (vorausgesetzt, dass die Sammlung auch eine Sammlung von shared_ptrs ist). Das ist das Modell, das ich die ganze Zeit in einem stark multi-Thread-Server – pm100

+0

Ich wusste nicht shared_ptr war thread sicher, aber darüber nachzudenken gibt es keinen Grund, es könnte nicht sein.Ich weiß, dass COM von Microsoft InterlockedIncrement und InterlockedDecrement verwendet, um eine sehr leichte threadsichere Implementierung durchzuführen. –