2013-06-19 10 views
8

Nie rozumiem dlaczego ten prosty fragment ma martwego Lock:std :: thread.join() impas

#include <atomic> 
#include <thread> 
#include <memory> 

using namespace std; 
class Test { 
public: 

    Test() : mExit(false) 
    { 
     mThread = thread(bind(&Test::func, this)); 
    } 

    ~Test() 
    { 
     if (mThread.joinable()) 
     { 
      mExit = true; 
      mThread.join(); 
     } 
    } 

private: 
    void func() 
    { 
     while (!mExit) 
     { 
      // do something 
     } 
    } 

private: 
    atomic<bool> mExit; 
    thread mThread; 
}; 

typedef unique_ptr<Test> TestPtr; 
TestPtr gTest; 

int main() 
{ 
    gTest = TestPtr(new Test); 
    return 0; 
} 

Edycja Wpisałem źle contstructor ustawić mExit = true

Edycja 2 Używam msvc2012 z zestawem narzędzi v110_xp.

Edycja 3 Problem znika, jeśli jawnie wywołać gTest.release() wewnątrz głównego

+3

'mExit = false' ?? –

+0

Napisałem źle, przepraszam. Problem pozostaje. –

+0

Hmm. Prawdopodobnie nie będzie lepiej, dopóki nie użyjesz atomic poprawnie. I użyj debuggera, aby dowiedzieć się, co robi wątek. Znaczne szanse, że jest wyłączone w chwastach, blokowanie niektórych wywołań systemu operacyjnego zamiast wypalania 100% rdzenia sprawdzającego ten stan wyjścia w kółko. –

Odpowiedz

6

Właśnie miałem ten problem, więc zamieszczam prawdziwą odpowiedź dla innych.

w visual studio przynajmniej tam jest „blokada exit”, która jest zablokowana, gdy wątek wchodzi kod wyjścia (tj. Po main() dla głównego wątku, a po f() dla std::thread(f)).

Gdy twoja klasa testowa zostanie zniszczona po zakończeniu main(), "blokada wyjścia" jest zablokowana. Tylko wtedy ustawisz mExit = true;, a drugi wątek zostanie ukończony. Ten inny wątek następnie czeka na uzyskanie "blokady wyjścia", która jest już zajęta przez główny wątek, podczas gdy główny wątek czeka w mThread.join(); powodując zakleszczenie.

Tak, musisz połączyć wszystkie swoje wątki przed zakończeniem wątku głównego.

3

Dla mnie kod wygląda w porządku, jeśli jej dobrze z miejscowym DUT złego z globalnym ja bym podejrzany klasa związane sekwencja deinitów. Łączenie odbywa się głęboko w wyjściu, a implementacja mogła już wyeliminować niektóre struktury. Nie powinno tak być, ale możliwe.

W każdym razie zawsze staram się unikać wątku początkowego przed głównym i pozostawiając jakikolwiek sięgający koniec głównego. Uważam, że to tylko proszenie o kłopoty. Jeśli możesz zmienić układ, aby wymusić połączenie w mniejszym punkcie, cały problem może zostać odparowany.

Powinieneś także używać atomowej flagi nad atomową.

+0

Czy mam jakieś zalety używania atomowej flagi nad atomowym lub atomic_bool? Muszę zbadać lepszą atomikę. –

+0

atomic_flag jest pewną prawdziwą rzeczą atomową, najbardziej podstawowym elementem. Inne typy mogą być implementowane z wewnętrznym muteksem. IMO jest mało prawdopodobne, ale po co ryzykować. –

+0

@BalogPal Ponieważ 'atomic_flag' jest królewskim bólem do użycia? ;) – ComicSansMS

0

Zmiana kodu z

gTest = TestPtr (nowy test);

do

auto numeru GTEST = std :: make_unique();

wyeliminować problem.

Problem jako punkt powyżej z obiektem globalnym.

Powiązane problemy