2010-10-09 17 views
7

Tengo una aplicación de servidor de subprocesos múltiples que necesita bloqueos mutex sobre alguna memoria compartida.Ejemplo de cómo usar aumentar los mutexes aumentables

La memoria compartida son básicamente mapas STL etc.

Gran parte del tiempo Sólo estoy leyendo desde el mapa. Pero, también tengo que agregarle ocasionalmente.

p. Ej. typedef std :: map MessageMap; MessageMap msgmap; boost: shared_mutex access_;

void ProcessMessage(Message* message) 
{ 
    // Access message... read some stuff from it message->... 

    UUID id = message->GetSessionID(); 

    // Need to obtain a lock here. (shared lock? multiple readers) 
    // How is that done? 
    boost::interprocess::scoped_lock(access_); 

    // Do some readonly stuff with msgmap 
    MessageMap::iterator it = msgmap.find(); 
    // 

    // Do some stuff... 

    // Ok, after all that I decide that I need to add an entry to the map. 
    // how do I upgrade the shared lock that I currently have? 
    boost::interprocess::upgradable_lock 


    // And then later forcibly release the upgrade lock or upgrade and shared lock if I'm not looking 
    // at the map anymore. 
    // I like the idea of using scoped lock in case an exception is thrown, I am sure that 
    // all locks are released. 
} 

EDIT: que podría ser confuso los diferentes tipos de bloqueo.

Cuál es la diferencia entre compartida/actualización y exclusiva. es decir, no entiendo la explicación. Parece que si solo desea permitir que muchos lectores, un acceso compartido es todo lo que desea obtener. Y para escribir en su memoria compartida solo necesita acceso de actualización. ¿O necesitas exclusividad? La explicación en el impulso es cualquier cosa menos clara.

Se ha obtenido acceso de actualización porque puede escribir. Pero compartir significa que definitivamente no escribirás ¿es eso lo que significa?

EDITAR: Permítanme explicarles lo que quiero hacer con un poco más de claridad. Todavía no estoy contento con las respuestas.

Aquí está el ejemplo una y otra vez, pero con un ejemplo de código que estoy usando también. Solo una ilustración, no el código real.

typedef boost::shared_mutex Mutex; 
typedef boost::shared_lock<Mutex> ReadLock; 
typedef boost::unique_lock<Mutex> WriteLock; 
Mutex mutex; 
typedef map<int, int> MapType; // Your map type may vary, just change the typedef 
MapType mymap; 

void threadoolthread() // There could be 10 of these. 
{ 
    // Add elements to map here 
    int k = 4; // assume we're searching for keys equal to 4 
    int v = 0; // assume we want the value 0 associated with the key of 4 

    ReadLock read(mutex); // Is this correct? 
    MapType::iterator lb = mymap.lower_bound(k); 
    if(lb != mymap.end() && !(mymap.key_comp()(k, lb->first))) 
    { 
     // key already exists 
    } 
    else 
    { 
     // Acquire an upgrade lock yes? How do I upgrade the shared lock that I already  have? 
     // I think then sounds like I need to upgrade the upgrade lock to exclusive is that correct as well? 

     // Assuming I've got the exclusive lock, no other thread in the thread pool will be able to insert. 
     // the key does not exist in the map 
     // add it to the map 
     { 
      WriteLock write(mutex, boost::adopt_lock_t()); // Is this also correct? 
      mymap.insert(lb, MapType::value_type(k, v)); // Use lb as a hint to insert, 
                 // so it can avoid another lookup 
     } 
     // I'm now free to do other things here yes? what kind of lock do I have here, if any? does the readlock still exist? 
    } 

Respuesta

11

Usted ha dicho que su aplicación es multiproceso, por lo que debe utilizar impulso :: hilo no boost :: entre procesos.

De la documentación (no probado) que debe hacerlo de esta manera:

typedef boost::thread::shared_mutex shared_mutex; 
boost::thread::upgrade_lock<shared_mutex> readLock(access_); 

// Read access... 

boost::thread::upgrade_to_unique_lock<shared_mutex> writeLock(readLock); 

// Write access.. 

También tenga en cuenta que usted adquiere it mientras se bloquea para acceso de lectura, por lo que alguien puede eliminar este nodo y que ya no es válida cuando llegas a la sección de escritura. EQUIVOCADO, lo siento.

EDIT: Creo que explanation en impulsar es claro. Vamos a tratar de reformular a usted de todos modos:

Hay tres tipos principales de los conceptos de exclusión mutua (no cuento TimedLockable ya que no está relacionada con su pregunta):

  • bloqueables — sólo un simple, propiedad exclusiva mutex. Si alguien bloquea() s, nadie puede bloquearlo() de nuevo hasta que el propietario lo desbloquee(). boost :: thread :: mutex implementa este concepto. Para bloquear este concepto en estilo RAII use lock_guard o unique_lock para una interfaz más compleja.
  • SharedLockable — es un Bloqueable con una propiedad "compartida" adicional. Puede obtener la propiedad exclusiva con lock() o la propiedad compartida con lock_shared().Si bloquea la parte compartida, no puede actualizar su propiedad a la exclusiva. Necesitas desbloquear_shared() y lock() otra vez, lo que significa que alguien más puede modificar el recurso protegido entre unlock_shared() y lock(). Es útil cuando sabes a priori qué tipo de acceso al recurso vas a hacer. shared_mutex implementa este concepto. Use lock_guard o unique_lock para obtener la propiedad exclusiva y shared_lock para obtener la propiedad compartida.
  • UpgradeLockable — es SharedLockable que le permite actualizar de propiedad compartida a propiedad exclusiva sin desbloquear. shared_mutex implementa este concepto también. Puede usar los bloqueos anteriores para obtener la propiedad exclusiva o compartida. Para obtener una propiedad compartida actualizable, use upgrade_lock y actualícela con upgrade_to_unique_lock.
+0

Lo siento, creo que tal vez quiero utilizar boost :: upgrade_lock y boost :: upgrade_to_unique_lock. Quizás puedas explicar la diferencia entre ellos. Ver mi pregunta editada. – Matt

+0

@Matt H: vea la respuesta editada. – ybungalobill

+0

Con UpgradeLockable, puede haber solo un hilo en ese estado, pero varios pueden estar en SharedLockable ¿es correcto? Entonces, ¿para que un bloqueo de actualización se convierta en un bloqueo único, todos los bloqueos compartidos deben desbloquearse correctamente? – Matt

5

No desea boost-interprocess si solo está utilizando un único proceso. Como el nombre de la biblioteca implica, se usa para comunicación entre procesos (IPC). Lo más probable es que desee utilizar el boost-threadmutex and locking concepts.

#include <boost/thread/locks.hpp> 
#include <boost/thread/shared_mutex.hpp> 

int 
main() 
{ 
    typedef boost::shared_mutex Mutex; 
    typedef boost::shared_lock<Mutex> ReadLock; 
    typedef boost::unique_lock<Mutex> WriteLock; 
    Mutex mutex; 

    { 
     // acquire read lock 
     ReadLock read(mutex); 

     // do something to read resource 
    } 

    { 
     // acquire write lock 
     WriteLock write(mutex, boost::adopt_lock_t()); 

     // do something to write resource 
    } 
} 

hay un post en la lista de correo impulso explicar esto también.

+1

Editar: gracias Sam. ¿Puedes echar un vistazo a mi ejemplo anterior que edité al final de la pregunta? ¿Sería ese el uso correcto? – Matt

+1

@Matt, en su caso, ya que el bloqueo de lectura se adquiere incondicionalmente al ingresar 'threadoolthread', creo que quiere usar' boost :: upgrade_to_unique_lock' que ybungalobill ha [descrito] (http://stackoverflow.com/questions/3896717/example-of-how-to-use-boost-actualizable-mutexes/3896816 # 3896816). Sin embargo, nunca he usado 'boost :: adopt_lock_t()' así que no estoy familiarizado con el comportamiento, tal vez funcione. –

+0

no utilizaría upgrade_to_unique_lock al comienzo de la función de grupo de subprocesos significa que solo un subproceso en el grupo de subprocesos podría ejecutarse a la vez? – Matt

Cuestiones relacionadas