Ce fil de discussion est précieux pour expliquer comment implémenter des verrous de lecteur / graveur avec Boost. Cela semble relativement simple et je l’aime vraiment beaucoup, mais il semble également utiliser un verrou non nommé et j’ai besoin d’une solution interprocess (n’a pas besoin d’être portable, mais uniquement de Windows).
Est-il possible d’avoir un interprocess shared_mutex
? Je vois qu’il y a un named_mutex
mais je ne peux pas le faire fonctionner avec shared_lock
autres verrous.
Tous les indicateurs sont appréciés.
[MODIFIER]
En attendant, je suis tombé sur ce fil qui touche presque le bout des doigts. J’ai deux problèmes:
named_upgradable_mutex
mais je ne suis pas tout à fait sûr) et Les commentaires ou les bonnes solutions sont toujours les bienvenus.
La documentation Boost.Interprocess décrit les soi-disant mutex évolutifs pris en charge et les opérations mutex extensible pour les deux types de mutex extensible pris en charge:
boost::interprocess::interprocess_upgradable_mutex
, un mutex extensible anonyme, non récursif, pouvant être placé dans la mémoire partagée ou dans des fichiers mappés en mémoire. boost::interprocess::named_upgradable_mutex
, un mutex extensible nommé non récursif. EDIT: Je crois que cela fonctionne:
#include #include #include #include #include #include #include #include #include #include // 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 lock(mutex); return counter; } void set_counter(int counter) { boost::interprocess::scoped_lock 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(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 (region.get_address()); for (int i = 0; i < 100000; ++i) { d.set_counter(i); std::cout << "writer_child: " << i << std::endl; } } }
J'ai essayé ceci sur un Mac avec le script suivant:
#!/usr/bin/env sh ./a.out reader_child & ./a.out reader_child & ./a.out writer_child & ./a.out reader_child & ./a.out reader_child &
(Vous devez d'abord commencer par le parent: ./a.out parent
)
La sortie indiquait un entrelacement des lignes "reader_child" et "writer_child" (toutes les lignes "reader_child" indiquant une valeur non nulle après la première ligne "writer_child"), ce qui semble fonctionner.