2015-04-25 7 views
12

Il mio problema è abbastanza comune, suppongo, ma mi fa impazzire:Come creare buffer di sicurezza thread-safe/POD?

Ho un'applicazione multi-thread con 5 thread. 4 di questi fili fanno il loro lavoro, come le comunicazioni di rete e di accesso file system locale, e quindi tutti scrivono loro uscita ad una struttura di dati di questa forma:

struct Buffer { 
    std::vector<std::string> lines; 
    bool has_been_modified; 
} 

The 5th stampe discussione questi buffer/strutture allo schermo:

Buffer buf1, buf2, buf3, buf4; 

... 

if (buf1.has_been_modified || 
    buf2.has_been_modified || 
    buf3.has_been_modified || 
    buf4.has_been_modified) 
{ 
    redraw_screen_from_buffers(); 
} 

Come proteggo i buffer vengano sovrascritti mentre sono in corso o letti o scritti a?

Non riesco a trovare una soluzione adeguata, anche se penso che questo deve essere un problema comune silenzioso.

Grazie.

+1

uso [mutex] (http://en.cppreference.com/w/cpp/thread/mutex) – Diego

+0

Grazie per la risposta. Non ho molta esperienza nel multi threading. Potresti fare un breve esempio? – dummy

+0

C'è qualche ragione particolare per cui stai chiedendo un POD? (nota che la risposta attualmente accettata non descrive un POD) – Hurkyl

risposta

9

È necessario utilizzare un mutex. La classe mutex è std::mutex. Con C++ 11 puoi usare std::lock_guard<std::mutex> per incapsulare il mutex usando RAII. Così si avrebbe cambiare il vostro Buffer struct per

struct Buffer { 
    std::vector<std::string> lines; 
    bool has_been_modified; 
    std::mutex mutex; 
}; 

e ogni volta che leggere o scrivere al buffer o has_been_modified si farebbe

std::lock_guard<std::mutex> lockGuard(Buffer.mutex); //Do this for each buffer you want to access 
... //Access buffer here 

e il mutex uscirà automaticamente dal lock_guard quando viene distrutta .

Ulteriori informazioni sui mutex here.

+0

Grazie! Quello è ciò di cui ho bisogno! – dummy

+1

@ user4832939 - mentre un mutex è ciò che stai chiedendo esplicitamente, sembra che la situazione che stai descrivendo sarebbe un caso d'uso valido per una variabile di condizione. Controlla la risposta di Schultz9999 per i dettagli. –

+0

Ahem: legge o modifica il buffer o anche il valore has_been_modified. Non solo modificare. (In particolare, è anche necessario bloccare le letture se è possibile che qualche altro thread possa scrivere contemporaneamente alla lettura) Cercare la definizione di che cosa è una condizione di competizione. –

4

È possibile utilizzare un mutex (o mutex) attorno ai buffer per garantire che non vengano modificati da più thread contemporaneamente.

// Mutex shared between the multiple threads 
std::mutex g_BufferMutex; 

void redraw_screen_from_buffers() 
{ 
    std::lock_guard<std::mutex> bufferLockGuard(g_BufferMutex); 
    //redraw here after mutex has been locked. 
} 

Quindi il codice di modifica del buffer dovrebbe bloccare lo stesso mutex quando i buffer vengono modificati.

void updateBuffer() 
{ 
    std::lock_guard<std::mutex> bufferLockGuard(g_BufferMutex); 
    // update here after mutex has been locked 
} 

This contiene alcuni esempi di mutex.

+0

errato, perché ciò significa non più di un buffer modificato al momento – Krab

+0

@Krab Quindi utilizzare un mutex per buffer e la funzione 'redraw_screen_from_buffers' blocca tutti i mutex prima del ridisegno. – lcs

+0

che è meglio :) – Krab

2

mutex sono una cosa molto carina quando si cerca di evitare dataraces, e sono sicuro che la risposta inviata da @Phantom soddisferà la maggior parte delle persone. Tuttavia, si dovrebbe sapere che questo non è scalabile per sistemi di grandi dimensioni.

Bloccando si stanno sincronizzando i fili. Poiché solo uno alla volta può accedere al vettore, la scrittura del thread nel contenitore farà attendere l'altro fino a che non finisca ... potrebbe essere un bene per te, ma provoca gravi colli di bottiglia nelle prestazioni quando sono necessarie prestazioni elevate.

La soluzione migliore sarebbe utilizzare una struttura senza blocco più complessa. Sfortunatamente non penso che ci sia una struttura lockfree nella STL.Un esempio di coda di lockfree è disponibile here

Utilizzando una tale struttura, i vostri 4 thread di lavoro sarebbero in grado di accodare i messaggi al contenitore, mentre il 5 ° li avrebbe dequeue, senza dataraces

More on lockfree datastructure can be found here !

Problemi correlati