2012-10-27 14 views
7

Mam wątek, który chcę zasiadać w pętli, dopóki nie będę gotowy do zakończenia programu, w którym to momencie chcę, żeby wyszło z pętli i wyjdź, abym mógł zadzwonić pod numer std::thread::join. W dniach C++ 03, po prostu użyłbym bool chronionego przez blokadę, aby powiedzieć wątkowi kiedy wyjść. Tym razem pomyślałem, że skorzystam z nowej biblioteki atomów (konkretnie std::atomic_bool), ale mam problem. Poniżej jest mój przypadek testowy:Używanie atomów z std :: thread w C++ 11

#include <atomic> 
#include <thread> 
#include <cstdio> 

using namespace std; 

void setBool(atomic_bool& ab) 
{ 
    ab = true; 
} 

int main() 
{ 
    atomic_bool b; 
    b = false; 
    thread t(setBool, b); 
    t.join(); 
    printf("Atomic bool value: %d\n", b.load()); 
    return 0; 
} 

Deklaracja thread t wypluwa this potworność gdy próbuję skompilować. Centralna część błędu wydaje się być:

nieważny inicjalizacji const odniesienia typu „std :: atomic_bool &” z rvalue typu „std :: atomic_bool”

Dlaczego czy nie mogę uzyskać odwołania do atomic_bool? Co powinienem zamiast tego zrobić?

+0

@NicolBolas Jak to zrobić? Czy blokowanie zmiennej za pomocą muteksu przed uzyskaniem dostępu do niej to standardowy sposób udostępniania danych między wątkami? –

+0

Och, racja. Nevermind ... –

Odpowiedz

13

Musisz jawnie przekazać ref do swojego wątku. Użycie std::ref utworzy std::reference_wrapper, która jest kopiowana i będzie zawierała ref do twojej funkcji.

thread t(setBool, std::ref(b)); 

W przeciwnym razie spróbuje skopiować twój atomowy, który jest niekopiowalny.

+0

Dlaczego próbuje wykonać kopię? Czy podanie nazwy zmiennej dla argumentu referencyjnego nie przekazuje tradycyjnie tej zmiennej przez odniesienie? –

+4

@ slavik262 tak, to prawda. Konstruktor wątków robi to, ponieważ wywołujesz funkcję, z której nie wiesz, kiedy zostanie wykonana, jeśli przekazałeś referencję, referencja może być nieważna, więc skopiuje twoje argumenty, aby bezpiecznie je przechowywać. Jeśli jawnie używasz ref-wrapper, Twoim zadaniem jest upewnić się, że obiekt przeżyje wątek. – inf

+0

Dzięki za wyjaśnienie! –

4

Jak wyjaśnił bambus, musisz zawijać obiekty za pomocą std::ref, jeśli naprawdę chcesz, aby były przekazywane przez referencję za pomocą konstruktora zmiennej argumentów std::thread. (To samo dotyczy std::async.) Aby uniknąć tego sprzecznego z intuicją zachowania, można użyć lambda, który zachowuje się dokładnie tak, jak można się spodziewać. Wystarczy użyć tego, aby stworzyć wątek:

thread t([&]{ setBool(b); }); 

Z lambda, nie ma potrzeby, aby ref/cref nonsens, gdy chcesz przekazać argumenty przez odniesienie.

+0

Dzięki!Doskonale zdaję sobie sprawę z lambd (są niesamowite) - chciałem tylko zminimalizować ilość magii C++ 11, której używałem do testowania, aby wyizolować problem. –

0

po prostu wpadł na to, jak dobrze, myślę, że można również rozwiązać problem poprzez przepuszczanie adresu do atomowy tak:

std::atomic<bool> b{false}; 
std::thread t(setBool, &b); 

Gdzie twoja funkcja przyjmuje wskaźnik do atomowa:

void setBool(std::atomic<bool>* ab) 

Nie jestem pewien, jaka jest akceptowana praktyka, przypuszczam, że można przekazać wskaźnik zerowy do atomowej w ten sposób, ale nie jestem pewien, dlaczego chciałbyś.