Czy istnieje różnica między tymi dwoma segmentami kodu:
void f() {
thread_local vector<int> V;
V.clear();
... // use V as a temporary variable
}
i
void f() {
static thread_local vector<int> V;
V.clear();
... // use V as a temporary variable
}
Backstory: pierwotnie miałem wektor STATIC V (do przechowywania niektórych wartości pośrednich, jest on czyszczony za każdym razem, gdy wchodzę do funkcji) i program jednowątkowy. Chcę przekształcić program w program wielowątkowy, więc muszę jakoś pozbyć się tego statycznego modyfikatora. Moim pomysłem jest przekształcenie każdego statycznego w thread_local i nie martwić się o nic innego? Czy takie podejście może przynieść odwrotny skutek?
thread_local
zmiennej lokalnej nie ma sensu zaczynać od… każdy wątek ma swój własny stos wywołań.static
zamiaststatic thread_local
nie inicjuje jednej instancji zmiennej dla każdego wątku.static
vs,static thread_local
ale raczej oauto
vsthread_local
, używając znaczeniaauto
(tj. Automatycznego przechowywania) sprzed C ++ 11 .Odpowiedzi:
Zgodnie ze standardem C ++
Oznacza to więc, że ta definicja
void f() { thread_local vector<int> V; V.clear(); ... // use V as a temporary variable }
jest równa
void f() { static thread_local vector<int> V; V.clear(); ... // use V as a temporary variable }
Jednak zmienna statyczna nie jest tym samym, co zmienna thread_local.
Aby rozróżnić te zmienne, standard wprowadza nowy termin „ czas trwania wątku” wraz ze statycznym czasem trwania.
źródło
static
iextern
dlatego nie implikuje klasy pamięci, a jedynie powiązanie ze zmiennymi thread_local nawet w wewnętrznych zasięgach.Tak, „pamięć lokalna wątku” jest bardzo podobna do „globalnej” (lub „pamięci statycznej”), tyle że zamiast „czasu trwania całego programu” masz „czas trwania całego wątku”. Tak więc zmienna lokalna bloku lokalnego wątku jest inicjowana, gdy kontrola przechodzi przez swoją deklarację po raz pierwszy, ale oddzielnie w każdym wątku i jest niszczona po zakończeniu wątku.
źródło
Kiedy używane z
thread_local
,static
jest implikowane w zakresie blokowym (patrz odpowiedź @ Vlada), wymagane dla członka klasy; Myślę, że oznacza połączenie dla zakresu przestrzeni nazw.Na 9,2 / 6:
Aby odpowiedzieć na pierwotne pytanie:
Nie ma wyboru, z wyjątkiem zmiennych o zakresie przestrzeni nazw.
Nie.
źródło
Lokalny magazyn wątków jest statyczny, ale zachowuje się zupełnie inaczej niż zwykły magazyn statyczny.
Podczas deklarowania zmiennej statycznej istnieje dokładnie jedno wystąpienie zmiennej. Kompilator / system wykonawczy gwarantuje, że zostanie on zainicjowany kiedyś, zanim faktycznie go użyjesz, bez określania dokładnego czasu (niektóre szczegóły tutaj pominięto).
C ++ 11 gwarantuje, że ta inicjalizacja będzie bezpieczna wątkowo, jednak przed C ++ 11 to bezpieczeństwo wątku nie było gwarantowane. Na przykład
static X * pointer = new X;
może przeciekać instancje X, jeśli więcej niż jeden wątek trafi w statyczny kod inicjujący w tym samym czasie.
Kiedy deklarujesz zmienną wątek lokalną, istnieje potencjalnie wiele wystąpień zmiennej. Możesz myśleć o nich jako o mapach indeksowanych przez identyfikator wątku. Oznacza to, że każdy wątek widzi własną kopię zmiennej.
Ponownie, jeśli zmienna zostanie zainicjowana, kompilator / system wykonawczy gwarantuje, że inicjalizacja nastąpi przed użyciem danych i że inicjalizacja nastąpi dla każdego wątku, który używa tej zmiennej. Kompilator gwarantuje również, że inicjacja będzie bezpieczna wątkowo.
Gwarancja bezpieczeństwa wątków oznacza, że może istnieć sporo zakulisowego kodu, który sprawi, że zmienna będzie zachowywać się tak, jak się tego spodziewasz - zwłaszcza biorąc pod uwagę, że kompilator nie ma możliwości z wyprzedzeniem dowiedzieć się, ile dokładnie wątków będzie istnieje w twoim programie i ile z nich dotknie zmiennej lokalnej wątku.
źródło