2012-10-03 17 views
8

Standard mówi: "Obiekt typu thread: id zapewnia ... pojedynczą odrębną wartość dla wszystkich obiektów wątku, które nie reprezentują wątku wykonania". Czy jest to pojedyncza/odrębna wartość w odniesieniu do operator==, czy jest to rzeczywista wartość pojedyncza/różna bitowo?Wymagania dla std :: thread :: id. Czy może być atomizowany?

Powód pytania: std::thread::id::id() MSVC2012 pozostawia śmieci w jednym z jego pól, a następnie łamie kod, który dokonuje porównania na std::atomic<std::thread::id> (ponieważ ten ostatni zależy od porównań bitowych).

Czy std::atomic<std::thread::id> jest konstrukcją prawną?

EDIT: dla odniesienia, kod wygląda tak:

while(!worker_id.compare_exchange_weak(no_id = thread_id_type(), self_id)) 
    sleep(); 

Odpowiedz

10

Po pierwsze, std::atomic<std::thread::id> jest legalne: std::thread::id musi być trywialnie kopiowalny (30.3.1.1p2), który spełnia wymagania std::atomic<> (29,5p1).

Jest to jednak klasa nieprzezroczysta, więc nie ma wymogu, aby wzór bitowy porównywanych obiektów był identyczny.

W związku z tym, jeśli używasz compare_exchange_weak lub compare_exchange_strong, może się to nie udać w przypadku porównywanych wartości.

Zatem rada jest użycie compare_exchange_weak w pętli pozostawiając wartość expected jako wynik poprzedniej iteracji.

W twoim przypadku, semantyka interpretować z pętli są: utrzymanie pętli podczas worker_id jest identyfikatorem innego wątku, albo worker_id był std::thread::id ale wymiana nie powiodło się. Można to osiągnąć z następujących czynności:

no_id=std::thread::id(); 
while((no_id!=std::thread::id()) || 
     !worker_id.compare_exchange_weak(no_id, self_id)){ 
    if(no_id!=std::thread::id()) no_id=std::thread::id(); 
    sleep(); 
} 

lub

no_id=std::thread::id(); 
while(!worker_id.compare_exchange_weak(
      (no_id!=std::thread::id())?(no_id=std::thread::id())?no_id, self_id)) 
    sleep(); 

to tylko zmienić wartość no_id jeśli jest niestd::thread::id().

+0

Dziękuję.Selektywne resetowanie 'no_id' jest miłym trikiem, teraz zaczynam się zastanawiać, dlaczego go nie widziałem :) – vpozdyayev

+0

Ale prawdopodobnie chciałbyś wywołać tylko uśpienie, jeśli" no_id! = Std :: thread :: id() " w pętli. – cmeerw

+0

@ cmeerw Tak --- Próbowałem tylko jak najwierniej odwzorować pętlę vpozdyayeva. Jeśli 'compare_exchange_weak' nie powiedzie się" fałszywie ", to w większości przypadków chcesz zapętlić się natychmiast, bez czekania. –

5

Zostało to omówione w LWG924. Zasadniczo nie można używać compare_exchange_strong, ale powinieneś być w stanie użyć compare_exchange_weak w pętli, np.

expected = current.load(); 
do { 
    desired = function(expected); 
} while (!current.compare_exchange_weak(expected, desired)); 

Edit: Bezwarunkowo resetowania wartości celowość pętli - na podstawie kodu dołączonego Myślę, że najlepszym rozwiązaniem byłoby wtedy:

no_id = std::thread::id(); 
while(!worker_id.compare_exchange_weak(no_id, self_id)) 
{ 
    if (no_id != std::thread::id()) 
    { 
    sleep(); 
    no_id = std::thread::id(); 
    } 
} 
+0

Używam 'compare_exchange_weak' w pętli i, niestety, to nie pomaga. BTW, tutaj problemem są niezainicjalizowane pola, a nie dopełnienie (wspomniane jako "powiązany, ale możliwy do oddzielenia problem" w twoim linku). Jestem świadomy, że notatka 29.6.5/26 dotycząca semantyki memcmp i compare_exchange_weak szybko się konwergowała, ale nadal nie widzę, w jaki sposób mogłaby ona działać, jeśli "current" i "expected" są bitowo-różnymi reprezentacjami tego samego (co na 'operator ==') wartość. – vpozdyayev

+0

Dodano przykład kodu do pytania. – vpozdyayev

Powiązane problemy