Tengo un contenedor (C++) en el que necesito operar de dos maneras, desde diferentes subprocesos: 1) Agregar y eliminar elementos, y 2) iterar a través de sus miembros. Claramente, elimine el elemento mientras la iteración está sucediendo = desastre. El código es como la siguiente:¿Cómo iterar sobre un contenedor de una manera segura para la ejecución de subprocesos?
class A
{
public:
...
void AddItem(const T& item, int index) { /*Put item into my_stuff at index*/ }
void RemoveItem(const T& item) { /*Take item out of m_stuff*/ }
const list<T>& MyStuff() { return my_stuff; } //*Hate* this, but see class C
private:
Mutex mutex; //Goes in the *Item methods, but is largely worthless in MyStuff()
list<T> my_stuff; //Just as well a vector or deque
};
extern A a; //defined in the .cpp file
class B
{
...
void SomeFunction() { ... a.RemoveItem(item); }
};
class C
{
...
void IterateOverStuff()
{
const list<T>& my_stuff(a.MyStuff());
for (list<T>::const_iterator it=my_stuff.begin(); it!=my_stuff.end(); ++it)
{
...
}
}
};
Una vez más, B::SomeFunction()
y C::IterateOverStuff()
están recibiendo llamadas de forma asíncrona. ¿Qué es una estructura de datos que puedo usar para asegurar que durante la iteración, my_stuff
esté 'protegido' para agregar o eliminar operaciones?
+1. Boost tiene una implementación de estos: http://www.boost.org/doc/libs/1_46_1/doc/html/thread/synchronization.html#thread.synchronization.mutex_types.shared_mutex –
@Evan, @larsmans No lo hago entiendo muy bien, ¿dónde lo pondría? Simplemente defínalo globalmente y póngalo en C :: Iterar ... así como en los métodos A? ¿Cómo 'sabe' si se está realizando lectura o escritura –
@Matt: es probable que tenga el mismo alcance/propiedad que la propia lista. Si la lista es global, entonces el bloqueo debe ser global. Si algún objeto posee la lista, entonces ese mismo objeto debe poseer el bloqueo. –