2010-11-17 10 views
7

Tengo varios hilos que modifican un vector stl y una lista stl.
Quiero evitar tener que tomar un bloqueo si el contenedor está vacío¿STL está vacío()?

¿Sería el siguiente código enhebrable? ¿Qué pasa si los artículos eran una lista o un mapa?

class A 
{ 
    vector<int> items 
    void DoStuff() 
    { 
     if(!items.empty()) 
     { 
      AquireLock(); 
      DoStuffWithItems(); 
      ReleaseLock(); 
     } 
    } 
} 
+0

Gracias por las respuestas. Para aclarar la pregunta: Se agregará otro hilo a los artículos. No se eliminará ningún otro subproceso de los elementos: solo se eliminarán dentro de DoStuffWithItems() y solo un subproceso llama a DoStuff(). Está bien si items.empty() devuelve falso mientras que otro hilo se está agregando a él. No está bien si items.empty() hace que la aplicación se bloquee si se le agrega otro hilo –

Respuesta

6

Depende de lo que esperas. Las otras respuestas son correctas que en general, los contenedores C++ estándar no son seguros para subprocesos, y además, que en particular su código no protege contra otro subproceso que modifica el contenedor entre su llamada al empty y la adquisición del bloqueo (pero este asunto no está relacionado con la seguridad del hilo de vector::empty).

Por lo tanto, para evitar malentendidos: Su código no garantiza items no estará vacío dentro del bloque.

Pero su código todavía puede ser útil, ya que todo lo que quiere hacer es evitar creaciones de bloqueo redundantes. Su código no da garantías, pero puede evitar una creación de bloqueo innecesario. No funcionará en todos los casos (otros hilos aún pueden vaciar el contenedor entre su cheque y el candado) pero en algunos casos. Y si todo lo que busca es una optimización al omitir un bloqueo redundante, entonces su código logra ese objetivo.

Sólo asegúrese de que cualquier real el acceso al contenedor es protegido por las cerraduras.

Por cierto, Lo anterior es, estrictamente hablando comportamiento indefinido: una implementación STL se permite teóricamente modificar mutable miembros dentro de la llamada a empty. Esto significa que la llamada aparentemente inofensiva (porque solo lectura) a emptypuede en realidad causar un conflicto. Desafortunadamente, no puede confiar en la suposición de que las llamadas de solo lectura son seguras con los contenedores STL.

En la práctica, sin embargo, estoy bastante seguro de que se vector::empty no modificar ningún miembros.Pero ya para list::empty estoy menos seguro. Si realmente desea garantiza, entonces bloquee cada acceso o no use los contenedores STL.

1

STL no es seguro y es vacío también. Si desea que el contenedor sea seguro, debe cerrar todos sus métodos mediante mutex u otra sincronización

3

No hay garantía de subprocesos en nada en los contenedores y algoritmos del STL.

Así, Nº

2

Independientemente de si o no vacía es seguro para subprocesos, su código no será, como está escrito, lograr su objetivo.

class A 
{ 
    vector<int> items 
    void DoStuff() 
    { 
     if(!items.empty()) 
     { 
      //Another thread deletes items here. 
      AquireLock(); 
      DoStuffWithItems(); 
      ReleaseLock(); 
     } 
    } 
} 

Una mejor solución es que se bloquee cada vez que trabaje con items (cuando se repite, conseguir artículos, la adición de elementos, comprobar el recuento/vacío, etc.), lo que proporciona su propia seguridad hilo. Por lo tanto, adquiera primero el candado, y luego, compruebe si el vector está vacío.

+0

Su punto (// Otro hilo elimina elementos aquí) es claro. Sin embargo, también es obvio que puede verificar empty() después de adquirir el bloqueo para estar seguro. –

+0

@skwllsp: un punto válido. Si 'empty()' es seguro para hilos, al verificar primero el vacío, bloquear y luego volver a verificar puede evitar un bloqueo innecesario. – Brian

0

Como ya se ha respondido, el código anterior no es seguro para subprocesos y es obligatorio el bloqueo antes de realmente hacer algo con el contenedor. Pero el siguiente debería tener un mejor rendimiento que siempre el bloqueo y no puedo pensar en una razón por la que puede ser inseguro. La idea aquí es que el bloqueo puede ser costoso y lo estamos evitando, cuando no es realmente necesario.

class A 
{ 
    vector<int> items; 
    void DoStuff() 
    { 
     if(!items.empty()) 
     { 
      AquireLock(); 
      if(!items.empty()) 
      { 
       DoStuffWithItems(); 
      } 
      ReleaseLock(); 
     } 
    } 
}