Ejemplo de impulso shared_mutex (lecturas múltiples / una escritura)?

Tengo una aplicación multiproceso que tiene que leer algunos datos a menudo, y ocasionalmente esos datos se actualizan. En este momento, un mutex mantiene el acceso seguro a esos datos, pero es costoso porque me gustaría que varios hilos puedan leerse simultáneamente y solo bloquearlos cuando se necesita una actualización (el hilo de actualización podría esperar a que los otros hilos terminen) .

Creo que esto es lo que se supone que boost::shared_mutex hace, pero no tengo claro cómo usarlo, y no he encontrado un ejemplo claro.

¿Alguien tiene un ejemplo simple que podría usar para comenzar?

Parece que harías algo como esto:

 boost::shared_mutex _access; void reader() { // get shared access boost::shared_lock lock(_access); // now we have shared access } void writer() { // get upgradable access boost::upgrade_lock lock(_access); // get exclusive access boost::upgrade_to_unique_lock uniqueLock(lock); // now we have exclusive access } 

1800 La información es más o menos correcta, pero hay algunos problemas que quería corregir.

 boost::shared_mutex _access; void reader() { boost::shared_lock< boost::shared_mutex > lock(_access); // do work here, without anyone having exclusive access } void conditional_writer() { boost::upgrade_lock< boost::shared_mutex > lock(_access); // do work here, without anyone having exclusive access if (something) { boost::upgrade_to_unique_lock< boost::shared_mutex > uniqueLock(lock); // do work here, but now you have exclusive access } // do more work here, without anyone having exclusive access } void unconditional_writer() { boost::unique_lock< boost::shared_mutex > lock(_access); // do work here, with exclusive access } 

También tenga en cuenta que, a diferencia de un shared_lock, solo un hilo puede adquirir un upgrade_lock al mismo tiempo, incluso cuando no está actualizado (lo que pensé que era incómodo cuando lo encontré). Entonces, si todos sus lectores son escritores condicionales, necesita encontrar otra solución.

Puede usar boost para crear un locking de lectura y escritura:

 #include  #include  typedef boost::shared_mutex Lock; typedef boost::unique_lock< Lock > WriteLock; typedef boost::shared_lock< Lock > ReadLock; Lock myLock; void ReadFunction() { ReadLock r_lock(myLock); //Do reader stuff } void WriteFunction() { WriteLock w_lock(myLock); //Do writer stuff } 

Solo para agregar algo más de información empírica, he estado investigando todo el tema de los lockings actualizables, y un ejemplo para impulsar shared_mutex (lecturas múltiples / una escritura)? es una buena respuesta al agregar la información importante de que solo un hilo puede tener un upgrade_lock, incluso si no está actualizado, eso es importante, ya que significa que no puede pasar de un locking compartido a uno único sin soltar primero el locking compartido. (Esto se ha discutido en otra parte, pero el hilo más interesante está aquí http://thread.gmane.org/gmane.comp.lib.boost.devel/214394 )

Sin embargo, encontré una diferencia importante (no documentada) entre un hilo esperando una actualización a un locking (es decir, necesita esperar a que todos los lectores liberen el locking compartido) y un locking de escritura esperando lo mismo (es decir, un único locking).

  1. El hilo que está esperando un unique_lock en shared_mutex bloquea la entrada de nuevos lectores, tienen que esperar la solicitud de los escritores. Esto asegura que los lectores no mueran de hambre a los escritores (sin embargo, creo que los escritores podrían matar de hambre a los lectores).

  2. El hilo que está esperando la actualización de un upgradeable_lock permite que otros hilos obtengan un locking compartido, por lo que este hilo podría faltar si los lectores son muy frecuentes.

Este es un tema importante a considerar, y probablemente debería documentarse.

Use un semáforo con un conteo que sea igual al número de lectores. Permita que cada lector tome una cuenta del semáforo para poder leer, de esa forma todos pueden leer al mismo tiempo. Luego, permita que el escritor tome TODOS los conteos de semáforos antes de escribir. Esto hace que el escritor espere a que todas las lecturas finalicen y luego bloquea las lecturas mientras escribe.

Gran respuesta de Jim Morris, me encontré con esto y me tomó un tiempo para entender. Aquí hay un código simple que muestra que después de enviar una “solicitud” para un impulso unique_lock (versión 1.54) bloquea todas las solicitudes de shared_lock. Esto es muy interesante ya que me parece que elegir entre unique_lock y upgradeable_lock permite si queremos prioridad de escritura o no.

También (1) en la publicación de Jim Morris parece contradecir esto: Boost shared_lock. Leer preferido?

 #include  #include  using namespace std; typedef boost::shared_mutex Lock; typedef boost::unique_lock< Lock > UniqueLock; typedef boost::shared_lock< Lock > SharedLock; Lock tempLock; void main2() { cout < < "10" << endl; UniqueLock lock2(tempLock); // (2) queue for a unique lock cout << "11" << endl; boost::this_thread::sleep(boost::posix_time::seconds(1)); lock2.unlock(); } void main() { cout << "1" << endl; SharedLock lock1(tempLock); // (1) aquire a shared lock cout << "2" << endl; boost::thread tempThread(main2); cout << "3" << endl; boost::this_thread::sleep(boost::posix_time::seconds(3)); cout << "4" << endl; SharedLock lock3(tempLock); // (3) try getting antoher shared lock, deadlock here cout << "5" << endl; lock1.unlock(); lock3.unlock(); }