2013-04-24 20 views
8

Ho una classe ConcurrentQueue che si basa su un utente fornito contenitore con un costruttore come questo ...Come posso bloccare un mutex in un elenco di inizializzatore?

ConcurrentQueue(const ConcurrentQueue& other) : m_Queue(other.m_Queue) {} 

Ma, ho bisogno di bloccare other s' mutex mentre è in corso la copia.

Opzione 1:

così ho potuto non usare il costruttore di copia a tutti, e fare ...

ConcurrentQueue(const ConcurrentQueue& other) : m_Queue(other.m_Queue) 
{ 
    std::lock_guard<std::mutex> lock(other.m_Mutex); 
    m_Queue = other.m_Queue; 
} 

ma non posso garantire che l'assegnazione di copia e copiare la costruzione sono equivalenti funzionalità.

Opzione 2:

ho potuto avere un metodo privato ...

std::queue<T, Container> GetQueue() const 
{ 
    std::lock_guard<std::mutex> lock(other.m_Mutex); 
    return m_Queue; 
} 

E poi nel costruttore fare questo ...

ConcurrentQueue(const ConcurrentQueue& other) : m_Queue(other.GetQueue()) {} 

Ma questo potenziale (a seconda dell'ottimizzazione) usa il costruttore di copie di m_Queue una sola volta e il costruttore di mosse una volta. E inoltre non posso garantire che una copia e una mossa siano equivalenti a una semplice copia. Inoltre, il contenitore fornito dall'utente potrebbe essere bizzarro ed essere copiabile ma non modificabile, il che potrebbe anche causare problemi con questo approccio.

Quindi, cosa devo fare?

risposta

9
ConcurrrentQueue::ConcurrrentQueue(
     ConcurrrentQueue const& other) 
    : m_Queue((std::lock_guard<std::mutex>(other.m_Mutex), 
       other.m_Queue)) 
{ 
} 

dovrebbe funzionare.

+0

Pensi che dovrebbe essere sempre fatto in questo modo? – 0x499602D2

+0

@ 0x499602D2 In realtà, penso che la situazione dovrebbe essere evitata. Non conosco abbastanza il tuo contesto attuale, o il problema che stai cercando di risolvere, per suggerire soluzioni alternative, ma so che non ho mai dovuto usare qualcosa del genere. In effetti, non riesco a pensare a un caso in cui ho copiato un contenitore tra i thread. –

1

Bloccare, creare una copia del contenuto e quindi scambiarlo con il membro. Almeno questo è il modo più semplice e IMHO più pulito. Un altro modo meno pulito consiste nell'utilizzare l'operatore virgola: (a, b) produce b, ma se a è un blocco con ambito, il temporaneo rimarrà attivo fino al successivo punto di sequenza, ad esempio fino a quando non si è utilizzato per inizializzare la copia locale.

Detto questo, ci sono due cose da considerare:

  • Forse la copia non è un'idea così intelligente in ogni caso ed il vostro disegno funziona bene solo se si disattiva la copia.
  • Se si ha accesso alla coda e si può leggerlo per la copia, questo non implica che il mutex debba già essere bloccato? In caso contrario, come sei sicuro di voler davvero copiare la coda? Non metto in dubbio che ci siano risposte che giustificano il design, ma è insolito.
Problemi correlati