2010-04-19 20 views
6

Supongamos que tengo una colección flujos seguros de las cosas (lo llaman un ThingList), y quiero añadir la siguiente función.punteros que regresan de una manera segura para los subprocesos

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

Pero al hacer esto, he delegado la responsabilidad de la seguridad de rosca al código de llamada, lo que tendría que hacer algo como esto:

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

Obviamente una cerradura RAII/desbloquear objeto sería simplifique/elimine try/catch/unlocks, pero aún así es fácil que la persona que llama lo olvide.

Hay algunas alternativas que he mirado:

  • Retorno cosa por valor, en lugar de un puntero - bien a menos que necesite modificar el cosa
  • Añadir función ThingList::setItemBar(string name, int value) - bien, pero éstos tienden a proliferar
  • devolver un objeto pointerlike que bloquea la lista de la creación y la abre de nuevo en la destrucción. No estoy seguro si esto es una buena/mala práctica ...

¿Cuál es el enfoque correcto para hacer frente a esto?

Respuesta

4

No hay nadie "enfoque correcto"; Depende de las necesidades de tu aplicación.

Si es posible, volver las cosas por su valor, o devolver una copia que la persona que llama puede hacer lo que quieran con.

Una variante de lo anterior es para devolver una copia modificable y, a continuación, proporcionar una manera de combinar atómicamente un objeto modificado en la lista. Algo así como:

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

Sin embargo, esto puede causar problemas si varios subprocesos intentan actualizar el mismo objeto.

La idea "objeto pointerlike" suena bien, pero sospecho que daría lugar a difíciles de encontrar errores cuando algunos de bloqueo no está siendo puesto en libertad en alguna parte.

Intentaré mantener todo el código de bloqueo/desbloqueo dentro de ThingList, por lo que las funciones ThingList::set... son probablemente lo que haría.

+0

El "Combinar" es agradable, pero hay un supuesto oculto que los objetos Cosa saben cómo ubicarse en la lista. También puede pasar "clave" para fusionarse, pero luego tiene el problema de fusionar un elemento que se ha eliminado ... – Roddy

3

tienda y volver impulso :: shared_ptr s

hay que bloquear durante el acceso, sino que está a salvo tras el desbloqueo

+1

boost :: shared_ptr no hace nada para proteger la seguridad de la hebra de la colección. –

+0

depende exactamente del problema de seguridad del hilo con el que intentas tratar. Debes bloquear cuando accedas a la colección (leer o escribir) pero debes hacerlo de todos modos. Al devolver una ptr compartida, al menos se garantiza que si la colección se cambia detrás de usted, usted todavía está OK (suponiendo que la colección también sea una colección de shared_ptrs). Este es el modelo que uso todo el tiempo en un servidor muy multiproceso – pm100

+0

No sabía que shared_ptr era seguro para subprocesos, pero al pensar en ello no hay ninguna razón por la que no podría serlo.Sé que el COM de Microsoft usa InterlockedIncrement y InterlockedDecrement para hacer una implementación segura de subprocesos muy livianos. –

Cuestiones relacionadas