2010-04-19 5 views
6

Supposons que je dispose d'une collection thread-safe de choses (appelons-la ThingList), et je souhaite ajouter la fonction suivante.Renvoyer des pointeurs de manière sûre pour les threads

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

Mais en faisant cela, je l'ai confié la responsabilité de la sécurité des threads au code d'appel, qui devrait faire quelque chose comme ceci:

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

Il est évident qu'un verrou RAII/déverrouiller l'objet serait simplifier/supprimer le try/catch/unlock, mais il est toujours facile pour l'appelant d'oublier.

Il y a quelques alternatives que j'ai regardé:

  • Thing Retour en valeur, au lieu d'un pointeur - bien à moins que vous devez modifier la chose
  • Ajouter la fonction ThingList::setItemBar(string name, int value) - fin, mais ils tendent à proliférer
  • Renvoyer un objet pointeur qui verrouille la liste à la création et la déverrouille à nouveau en cas de destruction. Vous ne savez pas si c'est une bonne ou une mauvaise pratique ...

Quelle est la bonne approche pour y faire face?

Répondre

4

Il n'y a pas une seule "bonne approche"; Cela dépend des besoins de votre application.

Dans la mesure du possible, renvoyez les éléments par valeur ou renvoyez une copie indiquant que l'appelant peut faire ce qu'il veut.

Une variante de ce qui précède est de retourner une copie modifiable, puis de fournir un moyen de fusionner de manière atomique un objet modifié dans la liste. Quelque chose comme:

Thing t = myThingList.getThing(key); 
t.setFoo(f); 
t.setBar(b); 
myThingList.merge(t);  // ThingList atomically updates the appropriate element 

Cependant, cela peut causer des problèmes si plusieurs threads tentent de mettre à jour le même objet. L'idée de "l'objet pointeur" semble cool, mais je soupçonne que cela conduirait à des bogues difficiles à trouver quand un verrou ne se libère pas quelque part.

Je voudrais essayer de garder tout le code de verrouillage/déverrouillage dans ThingList, donc les fonctions ThingList::set... sont probablement ce que je ferais.

+0

La « Merge » est agréable, mais il y a une hypothèse cachée que les objets Thing savent comment se localiser dans la liste. Vous pouvez également passer la "clé" pour fusionner, mais vous avez alors le problème de fusionner un élément qui a été supprimé ... – Roddy

3

magasin et retour boost :: shared_ptr s

vous devez verrouiller lors de l'accès, mais vous êtes en sécurité après le déverrouillage

+1

boost :: shared_ptr ne fait rien pour protéger la sécurité des threads de la collection. –

+0

cela dépend exactement quel problème de sécurité de thread que vous essayez de traiter. Vous devez vous verrouiller lorsque vous accédez à la collection (lire ou écrire) mais vous devez le faire quand même. En retournant un ptr partagé, vous garantissez au moins que si la collection est modifiée derrière vous, vous êtes toujours OK (en supposant que la collection est également une collection de shared_ptrs). C'est le modèle que j'utilise tout le temps dans un serveur fortement multi-threadé. – pm100

+0

Je ne savais pas que shared_ptr était sûr pour les threads, mais en y réfléchissant, il n'y a aucune raison pour que cela ne puisse pas être le cas.Je sais que COM de Microsoft utilise InterlockedIncrement et InterlockedDecrement pour effectuer une implémentation thread-weight très légère. –

Questions connexes