2009-05-04 16 views
13

Qualcuno sa dove posso trovare un'impianto che avvolge una mappa STL e la rende sicura? Quando dico thread safe intendo che offre solo l'accesso seriale alla mappa, un thread alla volta. In modo ottimale, questa mappa dovrebbe utilizzare solo i costrutti STL e/o boost.Mappa thread-safe C++

risposta

11

Non soddisfa i criteri che hai specificato, ma si potrebbe avere uno sguardo ai TBB contenitori. Si chiama così concurrent_hash_map che consente a più thread di accedere contemporaneamente ai dati nella mappa. Ci sono alcuni dettagli, ma tutto è ben documentato e può darti un'idea del "contenitore concorrente". A seconda delle esigenze questo potrebbe essere del tutto fuori luogo ...

+2

Questa libreria è dipendente dalla CPU Intel? –

1

Il boost shared_mutex fornirebbe il miglior approccio multi lettore/autore singolo per avvolgere una mappa standard in base ai propri vincoli. Non conosco alcuna implementazione "pre-costruita" che sposino questi due poiché il compito è generalmente banale.

+4

Il compito è tutt'altro che banale, almeno per farlo in modo efficiente, motivo per cui non troverete alcuna implementazione. –

+0

Ok, forse "banale" è la parola sbagliata. Non è difficile da fare, almeno nel contesto specifico su cui stai lavorando (a meno che tu non abbia dei requisiti molto specifici). – Joe

1

Questo dipende dall'applicazione da implementare. Una mappa "thread-safe" renderebbe le chiamate individuali nella mappa thread-safe, ma molte operazioni devono essere effettuate thread-safe attraverso le chiamate. L'applicazione che utilizza la mappa deve associare un mutex alla mappa e utilizzare tale mutex per coordinare gli accessi ad essa.

Provare a creare contenitori thread-safe è stato un errore in Java e sarebbe un errore in C++.

+7

Puoi spiegare perché è stato un errore fare contenitori antiscasso? – einpoklum

3

In genere non è una buona idea per le classi di raccolta fornire sicurezza thread, perché non possono sapere come vengono utilizzati. Sarai molto più utile implementando i tuoi meccanismi di blocco nei costrutti di livello superiore che utilizzano le raccolte.

+8

Perché non è una buona idea? Puoi indicarmi alcuni articoli? Semplicemente non capisco perché Java, C#/VB (.NET) e C++ abbiano tutte le librerie per le raccolte concorrenti se sono una cattiva idea. Le librerie sono rispettivamente: java.util.concurrent, System.Collections.Concurrent (.NET 4.0) e Intel's Threading Building Blocks. L'argomento è che si prenda semplicemente un colpo di prestazioni usando queste librerie? So che alcune delle collezioni restituiscono sempre un'istantanea "copia" per l'iterazione e così, quindi posso vedere come sarebbe più lento. –

+1

Non capisco perché quelle librerie abbiano collezioni thread-safe. –

+2

Non sta chiedendo una classe raccolta sicura da thread. Vuole un "costrutto di livello superiore", come hai detto, "avvolge" l'implementazione. – Matt

0

Prova questa libreria

http://www.codeproject.com/KB/threads/lwsync.aspx

Si è implementato in un approccio basato sulla moderna politica C++.

Ecco qualche taglio dal link per mostrare l'idea con il caso 'vettore'

typedef lwsync::critical_resource<std::vector<int> > sync_vector_t; 
sync_vector_t vec; 

// some thread: 
{ 
    // Critical resource can be naturally used with STL containers. 
    sync_vector_t::const_accessor vec_access = vec.const_access(); 
    for(std::vector<int>::const_iterator where = vec_access->begin(); 
     where != vec_access->end(); 
     ++where; 
     ) 
    std::cout << *where << std::endl; 
} 

sync_vector_t::accessor some_vector_action() 
{ 
    sync_vector_t::accessor vec_access = vec.access(); 
    vec_access->push_back(10); 
    return vec_access; 
    // Access is escalated from within a some_vector_action() scope 
    // So that one can make some other action with vector before it becomes 
    // unlocked. 
} 

{ 
    sync_vector_t::accessor vec_access = some_vector_action(); 
    vec_access->push_back(20); 
    // Elements 10 and 20 will be placed in vector sequentially. 
    // Any other action with vector cannot be processed between those two 
    // push_back's. 
} 
0

sono arrivato fino a questo (che sono sicuro che può essere migliorato a prendere più di due argomenti):

template<class T1, class T2> 
class combine : public T1, public T2 
{ 
public: 

    /// We always need a virtual destructor. 
    virtual ~combine() { } 
}; 

Questo permette di fare:

// Combine an std::mutex and std::map<std::string, std::string> into 
// a single instance. 
SCA::combine<std::mutex, std::map<std::string, std::string>> lockableMap; 

// Lock the map within scope to modify the map in a thread-safe way. 
{ 
    // Lock the map. 
    std::lock_guard<std::mutex> locked(lockableMap); 

    // Modify the map. 
    lockableMap["Person 1"] = "Jack"; 
    lockableMap["Person 2"] = "Jill"; 
} 

Se si desidera utilizzare uno std :: recursive_mutex e uno std :: set, che sarebbe anche funzionare.