2015-04-25 15 views
12

Mój problem jest dość powszechny Przypuszczam, ale doprowadza mnie do szału:Jak utworzyć bezpieczny dla wątków bufor/POD?

Mam wielowątkową aplikację z 5 wątkami. 4 z tych wątków wykonywać swoją pracę, jak komunikacji sieciowej i lokalnego dostępu do systemu plików, a następnie wszystko napisać swoje wyjście do struktury danych tego formularza:

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

5. nadrukami nić te buforowe/Konstrukcje do ekranu:

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(); 
} 

Jak chronić bufory przed zastąpieniem podczas gdy są one albo są odczytywane lub zapisywane?

Nie mogę znaleźć odpowiedniego rozwiązania, chociaż myślę, że to musi być cichy, wspólny problem.

Dzięki.

+1

użytku [mutexes] (http://en.cppreference.com/w/cpp/thread/mutex) – Diego

+0

Dziękuję za odpowiedź. Nie mam dużego doświadczenia w wielowątkowości. Czy mógłbyś podać krótki przykład? – dummy

+0

Czy istnieje jakiś szczególny powód, dla którego prosiłeś o POD? (zauważ, że obecnie zaakceptowana odpowiedź nie opisuje POD) – Hurkyl

Odpowiedz

9

Powinieneś użyć muteksu. Klasa mutex to std::mutex. W C++ 11 można użyć std::lock_guard<std::mutex> do enkapsulacji muteksa za pomocą RAII. Więc można zmienić Buffer struct do

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

i kiedy odczytu lub zapisu do bufora lub has_been_modified byś zrobił

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

i mutex zostanie automatycznie zwolniony przez lock_guard gdy jest zniszczona .

Możesz przeczytać więcej o muteksach here.

+0

Dziękujemy! To jest to, czego potrzebuję! – dummy

+1

@ user4832939 - podczas gdy muteks jest tym, o co wyraźnie prosisz, wydaje się, że opisywana sytuacja byłaby ważnym przypadkiem użycia dla zmiennej warunku. Sprawdź odpowiedź Schultz9999 na szczegóły. –

+0

Ahem: odczytaj lub zmodyfikuj bufor lub też has_been_modified bool. Nie tylko modyfikuj. (Dokładniej, musisz również zablokować czytanie, jeśli możliwe jest, że jakiś inny wątek może pisać w tym samym czasie co odczyt) Sprawdź definicję stanu wyścigu. –

4

Możesz użyć muteksu (lub muteksów) wokół buforów, aby upewnić się, że nie są one modyfikowane przez wiele wątków w tym samym czasie.

// 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. 
} 

Następnie kod modyfikacji bufora musiałby blokować ten sam muteks, gdy bufory są modyfikowane.

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

This zawiera przykłady muteksów.

+0

złe, ponieważ oznacza to nie więcej niż jeden bufor zmodyfikowany w czasie – Krab

+0

@Krab Następnie użyj muteksu na bufor, a funkcja 'redraw_screen_from_buffers' blokuje wszystkie muteksy przed ponownym rysowaniem. – lcs

+0

to jest lepsze :) – Krab

2

Mutex to bardzo miła rzecz, gdy próbujesz uniknąć datariaces i jestem pewien, że odpowiedź wysłana przez @Phantom zadowoli większość ludzi. Należy jednak wiedzieć, że nie jest to skalowalne dla dużych systemów.

Blokując synchronizujesz wątki. Ponieważ dostęp do wektora może uzyskać tylko jedna osoba, zapisanie wątku w kontenerze spowoduje, że drugie oczekiwanie na jego zakończenie ... może być dobre dla ciebie, ale powoduje poważne zranienie wydajności, gdy wymagana jest wysoka wydajność.

Najlepszym rozwiązaniem byłoby zastosowanie bardziej złożonej struktury wolnej od blokady. Niestety nie sądzę, by w STL istniała standardowa struktura bez blokady.Jeden exemple kolejki lockfree jest dostępny here

Stosując taką strukturę, swoje 4 wątków roboczych będzie mógł enqueue wiadomości do pojemnika podczas 5th można by je dequeue, bez dataraces

More on lockfree datastructure can be found here !

Powiązane problemy