2012-09-15 15 views
6

This thread es oro a la hora de explicar cómo implementar bloqueos de lector/escritor con Boost. Parece relativamente simple y realmente me encanta, pero también parece estar usando un bloqueo sin nombre y necesito una solución entre procesos (no necesita ser portátil, puede ser solo de Windows).Cerradura de lector/escritor entre procesos con Boost

¿Hay alguna manera de tener un interproceso shared_mutex? Veo que hay un named_mutex pero no puedo hacer que funcione con shared_lock de otros bloqueos.

Cualquier puntero es apreciado.

[EDIT]

Mientras tanto, me he encontrado con this thread que casi se golpea el clavo en la cabeza. Tengo dos cuestiones:

  1. que no muestra código completo (que supongo que necesito utilizar named_upgradable_mutex pero no estoy muy seguro) y
  2. no me gusta la respuesta para el escritor modificado" "que utiliza una clase no listada que desbloquea en destructor pero una secuencia de 3 llamadas sin formato en el mutex.

Los comentarios o buenas soluciones siguen siendo bienvenidos.

Respuesta

9

La documentación Boost.Interprocess describe el llamado upgradable mutexes que apoya y la upgradable mutex operations para los dos tipos de exclusión mutua actualizables soportados:

EDIT: Creo que esto funciona:

#include <iostream> 
#include <string> 
#include <unistd.h> 

#include <boost/scope_exit.hpp> 
#include <boost/interprocess/mapped_region.hpp> 
#include <boost/interprocess/shared_memory_object.hpp> 
#include <boost/interprocess/sync/interprocess_upgradable_mutex.hpp> 
#include <boost/interprocess/sync/scoped_lock.hpp> 
#include <boost/interprocess/sync/sharable_lock.hpp> 
#include <boost/interprocess/sync/upgradable_lock.hpp> 

// http://stackoverflow.com/questions/12439099/interprocess-reader-writer-lock-with-boost/ 

#define SHARED_MEMORY_NAME "SO12439099-MySharedMemory" 

struct shared_data { 
private: 
    typedef boost::interprocess::interprocess_upgradable_mutex upgradable_mutex_type; 

    mutable upgradable_mutex_type mutex; 
    volatile int counter; 

public: 
    shared_data() 
     : counter(0) 
    { 
    } 

    int count() const { 
     boost::interprocess::sharable_lock<upgradable_mutex_type> lock(mutex); 
     return counter; 
    } 

    void set_counter(int counter) { 
     boost::interprocess::scoped_lock<upgradable_mutex_type> lock(mutex); 
     this->counter = counter; 
    } 
}; 

int main(int argc, char *argv[]) 
{ 
    using namespace boost::interprocess; 

    if (argc != 2) { 
     std::cerr << "Usage: " << argv[0] << " WHICH" << std::endl; 
     return 1; 
    } 

    const std::string which = argv[1]; 
    if (which == "parent") { 
     shared_memory_object::remove(SHARED_MEMORY_NAME); 
     shared_memory_object shm(create_only, SHARED_MEMORY_NAME, read_write); 

     BOOST_SCOPE_EXIT(argc) { 
      shared_memory_object::remove(SHARED_MEMORY_NAME); 
     } BOOST_SCOPE_EXIT_END; 

     shm.truncate(sizeof (shared_data)); 

     // Map the whole shared memory into this process. 
     mapped_region region(shm, read_write); 

     // Construct the shared_data. 
     new (region.get_address()) shared_data; 

     // Go to sleep for a minute. 
     sleep(60); 

     return 0; 
    } else if (which == "reader_child") { 
     shared_memory_object shm(open_only, SHARED_MEMORY_NAME, read_write); 

     mapped_region region(shm, read_write); 
     shared_data& d = *static_cast<shared_data *>(region.get_address()); 

     for (int i = 0; i < 100000; ++i) { 
      std::cout << "reader_child: " << d.count() << std::endl; 
     } 
    } else if (which == "writer_child") { 
     shared_memory_object shm(open_only, SHARED_MEMORY_NAME, read_write); 

     mapped_region region(shm, read_write); 
     shared_data& d = *static_cast<shared_data *>(region.get_address()); 

     for (int i = 0; i < 100000; ++i) { 
      d.set_counter(i); 
      std::cout << "writer_child: " << i << std::endl; 
     } 
    } 
} 

yo probamos este en un Mac con la siguiente secuencia de comandos:

#!/usr/bin/env sh 
./a.out reader_child & 
./a.out reader_child & 
./a.out writer_child & 
./a.out reader_child & 
./a.out reader_child & 

(usted tiene que comenzar el padre primero: ./a.out parent)

La salida mostró intercalación de "reader_child" y "writer_chi" ld "líneas (con todas las líneas" reader_child "que muestran un valor distinto de cero después de la primera línea" writer_child "), por lo que parece estar funcionando.

+0

Gracias! El truco para mí a pesar de que no es exactamente lo que estaba buscando despejó algunas dudas. – wpfwannabe

+0

¿por qué usa volátil cuando el contador está protegido por un bloqueo? –

+0

@BryanFok: utilicé 'volátil' porque no vi ninguna garantía de barrera de memoria al bloquear un' interprocess_upgradable_mutex'. Hay tres implementaciones: posix, windows y spin. Si utilizo las implementaciones de posix o windows, no creo que sea necesario 'volátil' porque pthread_mutex_lock()/WaitForSingleObject() se llama detrás de escena. La implementación de giro utiliza una operación CAS atómica, y creo que hay arquitecturas donde CAS no tiene garantías de barrera de memoria. Ver [esta respuesta] (http://stackoverflow.com/a/24143387/196844), por ejemplo. –

Cuestiones relacionadas