2012-12-08 14 views
7

Sto cercando di costruire una mappa nella memoria condivisa del seguente tipoMappa di <int, void*> nella memoria condivisa utilizzando boost :: interprocess

ho creare la regione di memoria condivisa in questo modo:

managed_shared_memory segment(create_only ,"MyMap" ,size);  

ShMemAllocator_t alloc_inst (segment.get_segment_manager()); 

map = segment.construct<MyMap_t>("MyMap")  
          (std::less<int>() 
          ,alloc_inst); 

Il valori nella mappa sono i seguenti:

 typedef pair<MutexType, boost::interprocess::offset_ptr<void> > ValueType ; 

MutexType è di per sé una struttura contenente una lettura e un mutex scrittura (usando read_lock e write_lock); definiti come segue:

typedef struct mutex_struct{ 
    sharable_lock<interprocess_mutex> read_lock(interprocess_mutex, defer_lock); 
    scoped_lock<interprocess_mutex> write_lock(interprocess_mutex, defer_lock); 
} MutexType; 

"dimensione" è la dimensione totale della mappa (in termini di oggetti, quindi la somma delle dimensioni dei dati indicate da tutti i puntatori void).

Come posso garantire che anche questi dati nulli * si trovino in questo segmento di memoria che ho creato, come posso istanziarlo all'interno dell'area di memoria condivisa esistente). La ragione per fare questo è che voglio allocare questo grande buffer una volta sola, ma rimuovendo/aggiungendo ripetutamente degli oggetti (la mappa modella una cache) Devo ancora trovare un modo in cui più oggetti possono essere allocati all'interno dello stesso segmento di memoria all'interno di una mappa. Inoltre, il tentativo di allocare la coppia MutexType restituisce un errore di compilazione che indica che non viene fornito alcun operatore di "chiamata".

risposta

11

Sei praticamente già lì. Chiama qualsiasi tipo di oggetto che stai allocando nella memoria condivisa SecondValue_t. Invece di ShMemAllocator_t, definire un diverso tipo di allocatore di interprocessi, ad esempio SecondValueAllocator_t, per allocare gli oggetti SecondValue_t. Ogni volta che si desidera inserire un oggetto ValueType nella mappa, il secondo valore dell'oggetto ValueType viene assegnato con l'istanza SecondValueAllocator_t.

Ecco un esempio completo, in parte utilizzando il codice in my answer per Interprocess reader/writer lock with Boost:

#include <cstdlib> 
#include <functional> 
#include <iostream> 
#include <string> 
#include <utility> 

#include <boost/scope_exit.hpp> 
#include <boost/interprocess/managed_shared_memory.hpp> 
#include <boost/interprocess/allocators/allocator.hpp> 
#include <boost/interprocess/allocators/private_node_allocator.hpp> 
#include <boost/interprocess/containers/map.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> 

#define SHARED_MEMORY_NAME "SO13783012-MyMap" 

// https://stackoverflow.com/questions/13783012/map-of-int-void-in-shared-memory-using-boostinterprocess 

using namespace boost::interprocess; 

typedef int SecondValue_t; 
typedef allocator<SecondValue_t, managed_shared_memory::segment_manager> SecondValueAllocator_t; 

typedef struct mutex_struct { 
    //... 
} MutexType; 

typedef std::pair<MutexType, SecondValueAllocator_t::pointer> ValueType; 

typedef map<int, ValueType>::value_type MyMapValueType; 
typedef allocator<MyMapValueType, managed_shared_memory::segment_manager> MyMapEntryAllocator_t; 
typedef map<int, ValueType, std::less<int>, MyMapEntryAllocator_t> MyMap_t; 

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

    mutable upgradable_mutex_type mutex; 
    MyMap_t my_map; 

public: 
    shared_data(const MyMapEntryAllocator_t& alloc) 
     : my_map(MyMap_t::key_compare(), alloc) 
    { 
    } 

    // Tries to get the mapped value for the given key `k'. If successful, the mapped value is 
    // copied into `out' and `true' is returned. Otherwise, returns `false' and does not modify 
    // `out'. 
    bool try_get(MyMap_t::mapped_type& out, MyMap_t::key_type k) const { 
     boost::interprocess::sharable_lock<upgradable_mutex_type> lock(mutex); 
     MyMap_t::const_iterator pos = my_map.find(k); 
     if (pos != my_map.end()) { 
      out = pos->second; 
      return true; 
     } 
     return false; 
    } 

    void put(MyMap_t::key_type k, MyMap_t::mapped_type v) { 
     boost::interprocess::scoped_lock<upgradable_mutex_type> lock(mutex); 
     my_map.insert(MyMap_t::value_type(my_map.size(), v)); 
    } 
}; 

int main(int argc, char *argv[]) 
{ 
    if (argc != 2) { 
     std::cerr << "Usage: " << argv[0] << " WHICH\n"; 
     return EXIT_FAILURE; 
    } 

    const std::string which = argv[1]; 

    if (which == "parent") { 
     shared_memory_object::remove(SHARED_MEMORY_NAME); 
     BOOST_SCOPE_EXIT(argc) { 
      shared_memory_object::remove(SHARED_MEMORY_NAME); 
     } BOOST_SCOPE_EXIT_END; 
     managed_shared_memory shm(create_only, SHARED_MEMORY_NAME, 65536); 

     MyMapEntryAllocator_t entry_alloc(shm.get_segment_manager()); 
     shared_data& d = *shm.construct<shared_data>("theSharedData")(entry_alloc); 

     SecondValueAllocator_t second_value_alloc(shm.get_segment_manager()); 

     // Insert some test data. 
     SecondValueAllocator_t::pointer p; 
     p = second_value_alloc.allocate(1); 
     second_value_alloc.construct(p, -3); 
     d.put(0, std::make_pair(MutexType(), p)); 
     p = second_value_alloc.allocate(1); 
     second_value_alloc.construct(p, 70); 
     d.put(1, std::make_pair(MutexType(), p)); 
     p = second_value_alloc.allocate(1); 
     second_value_alloc.construct(p, -18); 
     d.put(2, std::make_pair(MutexType(), p)); 
     p = second_value_alloc.allocate(1); 
     second_value_alloc.construct(p, 44); 
     d.put(3, std::make_pair(MutexType(), p)); 
     p = second_value_alloc.allocate(1); 
     second_value_alloc.construct(p, 0); 
     d.put(4, std::make_pair(MutexType(), p)); 

     // Go to sleep for a minute - gives us a chance to start a child process. 
     sleep(60); 
    } else { 
     managed_shared_memory shm(open_only, SHARED_MEMORY_NAME); 
     std::pair<shared_data *, std::size_t> find_res = shm.find<shared_data>("theSharedData"); 
     if (!find_res.first) { 
      std::cerr << "Failed to find `theSharedData'.\n"; 
      return EXIT_FAILURE; 
     } 
     shared_data& d = *find_res.first; 

     MyMap_t::mapped_type v; 
     int i = 0; 
     for (; d.try_get(v, i); ++i) { 
      std::cout << i << ": " << *v.second << '\n'; 
     } 

     // Add an entry. 
     srand(time(NULL)); 
     SecondValueAllocator_t second_value_alloc(shm.get_segment_manager()); 
     SecondValueAllocator_t::pointer p = second_value_alloc.allocate(1); 
     second_value_alloc.construct(p, (rand() % 200) - 100); 
     d.put(i, v = std::make_pair(MutexType(), p)); 
     std::cout << "placed " << *v.second << " into the map.\n"; 
    } 

    return EXIT_SUCCESS; 
} 

verificare il lavoro svolto avviando il processo padre prima:

 
./SO13783012 parent 

Poi alcuni bambini:

 
./SO13783012 child 

Uscita campione:

 
> ./SO13783012 child 
0: -3 
1: 70 
2: -18 
3: 44 
4: 0 
placed 5: -63 into the map. 
> ./SO13783012 child 
0: -3 
1: 70 
2: -18 
3: 44 
4: 0 
5: -63 
placed 6: -42 into the map. 
> ./SO13783012 child 
0: -3 
1: 70 
2: -18 
3: 44 
4: 0 
5: -63 
6: -42 
placed 7: -28 into the map. 
+0

(so che questo è un po 'vecchio ma) ho notato che il blocco del writer non funziona davvero nel tuo esempio.Se si generano più writer child il valore di i potrebbe essere indefinito e si proverebbe a inserire una coppia utilizzando lo stesso valore, a causa di problemi di concorrenza - Se quell'esempio dovrebbe mostrare solo l'aggiunta di un'altra voce dopo l'ultima chiave - che il metodo put deve raccogliere la dimensione corrente della mappa e inserisci l'elemento alla dimensione + 1. – Steve

+0

Ciao @Steve, non sono sicuro di seguirlo. Perché il valore di "i" non è definito? –

+1

Nel ciclo for - si conta ++ i fino a quando non viene restituito alcun valore da d.try_get - supponiamo che i sia ora 10. In seguito, si tenta di inserire la chiave i = 10 con d.put (i, v = std :: make_pair (MutexType(), p)) ;. Se nel frattempo un altro processo di scrittura di un bambino ha già inserito qualcosa nella mappa, 10 sarebbe un duplicato. Prendi solo 2 autori di testi - ognuno dei quali esegue una riga alla volta - entrambi arrivano a i = 10, ma child1 inserisce prima una nuova voce con i = 10, quindi il secondo figlio fallirà. Questo perché i = 10 è al di fuori di qualsiasi blocco di scrittura/lettura – Steve

0

È possibile utilizzare rebind in allocatore <>

// convert an allocator<T> to allocator<U> 
template<typename U> 
struct rebind { 
    typedef Allocator<U> other; 
}; 

per fare un

typedef std::allocator< char, managed_shared_memory::segment_manager > char_alloc; 

quindi allocare la memoria come questo

char_alloc char_alloc_obj; 
char * ptr = new (char_alloc_obj.allocate(size)) char[size]; 
void * vptr = (void *) ptr; 

Lo std :: allocator predefinito <> è lo stato di meno. L'allocatore di memoria condivisa avrà lo stato quindi è necessario capire come copiare lo stato tra allocatori di tipi diversi.

Problemi correlati