2009-11-03 12 views
30

Zakładam, że łączenie to wskazywałoby, jednak nie wydaje się, żeby tak było.Jak mogę rzetelnie stwierdzić, czy wątek boost zakończył działanie?

W klasie pracowników, starałem się wskazywać, że to wciąż przetwarzanie przez orzecznika:

bool isRunning(){return thread_->joinable();} 

Czy nie wątku, który odszedł nie być PŁYCIE? Czego mi brakuje ... Jakie jest znaczenie wątku boost :: joinable?

Odpowiedz

30

Ponieważ można dołączyć do wątku, nawet po jego zakończeniu, joinable() będzie nadal zwracać wartość true, dopóki nie wywołasz join() lub odłącz(). Jeśli chcesz się dowiedzieć, czy wątek nadal działa, powinieneś móc wywołać funkcję timed_join z czasem oczekiwania równym 0. Zauważ, że może to spowodować stan wyścigu, ponieważ wątek może zakończyć się tuż po zakończeniu połączenia.

+6

To trochę mylące stwierdzenie, że może to doprowadzić do stanu wyścigowego. Sam 'timed_join' nie może tego zrobić. jeśli popełnisz jakieś błędne założenia w oparciu o wynik połączenia, możesz oczywiście skończyć z warunkiem wyścigu, ale to nie ma nic wspólnego z 'timed_join' niż z tobą, zakładając, że wynik tego połączenia jest nadal ważny. W każdym razie +1 – jalf

+35

Myślę, że to jest naprawdę złe. Dlaczego projektanci wspomagania nigdy nie myślą o intuicji ani o początkujących. Wystarczyłaby prosta metoda isRunning(). Zamiast tego zmuszają one do używania funkcji, która nie powinna być intuicyjnie użyta w tym przypadku. Nie chcę próbować dołączać do wątku, chcę tylko szybko sprawdzić, czy nadal coś robi. To jest bzdura. Zmarnowałem dużo czasu, zanim to znalazłem. To nie jest cholerne słowo w "docs". – AndreasT

+0

Wątek może być w 3 stanach: Bieganie, Wolnostojący, Notowanie. –

3

Zasadniczo nie możesz tego zrobić. Powodem jest to, że dwiema możliwymi odpowiedziami są "Tak" i "Nie, kiedy ostatnio wyglądałem, ale może teraz". Nie ma niezawodnego sposobu na stwierdzenie, że wątek nadal znajduje się w jego metodzie run, nawet jeśli istnieje niezawodny sposób określenia czegoś przeciwnego.

+7

Zasadniczo możesz to zrobić. Możesz rzetelnie zapytać lub "obserwować" status wątku w danym momencie. Problem polega na tym, że nie możesz wysuwać żadnych założeń dotyczących interakcji w oparciu o otrzymany status, co oznacza, że ​​w momencie, w którym masz informacje "wątek wciąż działa", mógł już zostać zatrzymany w czasie, który potrzebował, aby uzyskać te informacje, ale to rzadko ma znaczenie krytyczne. Przepraszamy, ale ten wpis nie był w żaden sposób pomocny. – AndreasT

+0

@AndreasT: Jeśli nie możesz zrobić żadnych założeń, jak to może być przydatne? –

5

Użyj thread::timed_join() z minimalnym limitem czasu. Zwróci wartość false, jeśli wątek nadal działa.

+0

To jest fałsz. Jeśli wątek został odłączony, zwróci false. Rzeczywiście, musisz przeczytać to na odwrót: jeśli zwrot jest prawdziwy, wątek działał, a następnie zatrzymał się podczas timeout. –

+0

@GaetanoMendola: Nie do końca, wątek mógł zostać zatrzymany i złączony, gdy zadzwonisz timed_join, a wynik będzie prawdziwy. –

0

Jest to nieco surowy, ale już teraz nadal działa zgodnie z moimi wymaganiami. :) Używam boost 153 i qt. Stworzyłem wektor int do śledzenia "statusu" moich wątków. Za każdym razem, gdy utworzę nowy wątek, dodaję jeden wpis do wątku thread_ids z wartością 0. Dla każdego utworzonego wątku przekazuję identyfikator, dzięki czemu wiem, jaką część wątków thread_ids mam aktualizować. Ustaw status na 1 dla bieżących i innych wartości w zależności od aktualnie wykonywanej aktywności, więc wiem, jakie czynności zostały wykonane po zakończeniu wątku. 100 to wartość ustawiona dla poprawnie ukończonego wątku. Nie jestem pewien, czy to pomoże, ale jeśli masz inne sugestie, jak to poprawić, daj mi znać. :)

std::vector<int> thread_ids; 
const int max_threads = 4; 
void Thread01(int n, int n2) 
{ 
    thread_ids.at(n) = 1; 
    boost::this_thread::sleep(boost::posix_time::milliseconds(n2 * 1000)); 
    thread_ids.at(n) = 100; 
    qDebug()<<"Done "<<n; 

} 
void getThreadsStatus() 
{ 
    qDebug()<<"status:"; 
    for(int i = 0; i < max_threads, i < thread_ids.size(); i++) 
    { 
     qDebug()<<thread_ids.at(i); 
    } 
} 
int main(int argc, char *argv[]) 
{ 
    for(int i = 0; i < max_threads; i++) 
    { 
     thread_ids.push_back(0); 
     threadpool.create_thread(
      boost::bind(&boost::asio::io_service::run, &ioService)); 
     ioService.post(boost::bind(Thread01, i, i + 2)); 
     getThreadsStatus(); 
    } 

    ioService.stop(); 
    threadpool.join_all(); 
    getThreadsStatus(); 
} 
0

Najprostszym sposobem, jeśli funkcja, która uruchamia twój wątek jest wystarczająco prosta, jest ustawienie zmiennej na wartość true, gdy funkcja jest zakończona. Oczywiście, potrzebujesz zmiennej na wątek, jeśli masz wiele map z identyfikatorami wątków, a stan może być lepszym rozwiązaniem. Wiem, że jest ręcznie, ale w międzyczasie działa dobrze.

class ThreadCreator 
{ 
private: 
    bool   m_threadFinished; 
    void launchProducerThread(){ 
     // do stuff here 
     m_threadRunning = true; 
    } 
public: 
    ThreadCreator() : m_threadFinished(false) { 
     boost::thread(&Consumer::launchProducerThread, this); 
    } 
}; 
0

To nie może być bezpośrednią odpowiedź na Twoje pytanie, ale widzę pojęcie wątku jako mechanizm bardzo lekkiego i celowo pozbawiona czegokolwiek z wyjątkiem mechanizmów synchronizacji. Myślę, że właściwym miejscem do umieszczenia "działa" jest klasa, która definiuje funkcję wątku. Zwróć uwagę, że z perspektywy projektowania możesz opuścić wątek przy przerwaniu i nadal nie masz ukończonej pracy. Jeśli chcesz wyczyścić wątek po jego zakończeniu, możesz zawinąć go w bezpieczny wskaźnik i przekazać go klasie robotniczej.

+0

Uważam, że byłoby lepiej, gdyby wyjaśniasz za pomocą przykładów kodu i dzielisz tekst na akapity, aby ułatwić czytelność. – phaberest

Powiązane problemy