Como verificar se um std :: thread ainda está em execução?

Como posso verificar se um std::thread ainda está em execução (de maneira independente da plataforma)? Falta um método timed_join() e joinable() não é para isso.

Eu pensei em bloquear um mutex com um std::lock_guard no thread e usando o método try_lock() do mutex para determinar se ele ainda está bloqueado (o thread está sendo executado), mas parece desnecessariamente complexo para mim.

Você conhece um método mais elegante?

Atualização: Para ser claro: eu quero verificar se o segmento saiu ou não. Um thread ‘pendente’ é considerado em execução para essa finalidade.

    Se você está disposto a fazer uso de C ++ 11 std::async e std::future para executar suas tarefas, então você pode utilizar a function wait_for de std::future para verificar se o encadeamento ainda está sendo executado de uma maneira simples como isso:

     #include  #include  #include  #include  int main() { using namespace std::chrono_literals; /* Run some task on new thread. The launch policy std::launch::async makes sure that the task is run asynchronously on a new thread. */ auto future = std::async(std::launch::async, [] { std::this_thread::sleep_for(3s); return 8; }); // Use wait_for() with zero milliseconds to check thread status. auto status = future.wait_for(0ms); // Print status. if (status == std::future_status::ready) { std::cout < < "Thread finished" << std::endl; } else { std::cout << "Thread still running" << std::endl; } auto result = future.get(); // Get result. } 

    Se você deve usar std::thread então você pode usar std::promise para obter um object futuro:

     #include  #include  #include  #include  int main() { using namespace std::chrono_literals; // Create a promise and get its future. std::promise p; auto future = p.get_future(); // Run some task on a new thread. std::thread t([&p] { std::this_thread::sleep_for(3s); p.set_value(true); // Is done atomically. }); // Get thread status using wait_for as before. auto status = future.wait_for(0ms); // Print status. if (status == std::future_status::ready) { std::cout < < "Thread finished" << std::endl; } else { std::cout << "Thread still running" << std::endl; } t.join(); // Join thread. } 

    Ambos os exemplos produzirão:

     Thread still running 

    Isto é claro, porque o status do encadeamento é verificado antes que a tarefa seja finalizada.

    Mas, novamente, pode ser mais simples fazê-lo como outros já mencionaram:

     #include  #include  #include  #include  int main() { using namespace std::chrono_literals; std::atomic done(false); // Use an atomic flag. /* Run some task on a new thread. Make sure to set the done flag to true when finished. */ std::thread t([&done] { std::this_thread::sleep_for(3s); done = true; }); // Print status. if (done) { std::cout < < "Thread finished" << std::endl; } else { std::cout << "Thread still running" << std::endl; } t.join(); // Join thread. } 

    Editar:

    Há também o std::packaged_task para uso com o std::thread para uma solução mais limpa do que usar o std::promise :

     #include  #include  #include  #include  int main() { using namespace std::chrono_literals; // Create a packaged_task using some task and get its future. std::packaged_task task([] { std::this_thread::sleep_for(3s); }); auto future = task.get_future(); // Run task on new thread. std::thread t(std::move(task)); // Get thread status using wait_for as before. auto status = future.wait_for(0ms); // Print status. if (status == std::future_status::ready) { // ... } t.join(); // Join thread. } 

    Uma solução fácil é ter uma variável booleana que o encadeamento define como true em intervalos regulares, e isso é verificado e configurado como false pelo encadeamento que deseja saber o status. Se a variável for false para long, o thread não será mais considerado ativo.

    Uma maneira mais thread-safe é ter um contador que é aumentado pelo thread filho, e o thread principal compara o contador para um valor armazenado e se o mesmo após muito tempo, em seguida, o thread filho é considerado não ativo.

    Note, no entanto, não há nenhuma maneira em C ++ 11 para realmente matar ou remover um segmento que foi enforcado.

    Editar Como verificar se um segmento saiu ou não: Basicamente, a mesma técnica descrita no primeiro parágrafo; Ter uma variável booleana inicializada como falsa. A última coisa que o encadeamento filho faz é configurá-lo como verdadeiro. O thread principal pode então verificar essa variável e, se for verdade, fazer uma junit no thread filho sem muito (se houver) bloqueio.

    Edit2 Se o thread sai devido a uma exceção, então tem duas funções “principais” de thread: A primeira tem um trycatch dentro do qual ela chama a segunda function de thread principal “real”. Esta primeira function principal define a variável “have_exited”. Algo assim:

     bool thread_done = false; void *thread_function(void *arg) { void *res = nullptr; try { res = real_thread_function(arg); } catch (...) { } thread_done = true; return res; } 

    Este mecanismo simples que você pode usar para detectar o acabamento de um thread sem bloquear no método de junit.

     std::thread thread([&thread]() { sleep(3); thread.detach(); }); while(thread.joinable()) sleep(1); 

    Crie um mutex que o segmento em execução e o segmento de chamada ambos tenham access. Quando o thread em execução inicia, bloqueia o mutex e, quando termina, desbloqueia o mutex. Para verificar se o segmento ainda está em execução, o segmento de chamada chama mutex.try_lock (). O valor de retorno disso é o status do encadeamento. (Apenas certifique-se de desbloquear o mutex se o try_lock funcionou)

    Um pequeno problema com isso, mutex.try_lock () retornará false entre o tempo que o thread é criado e quando ele bloqueia o mutex, mas isso pode ser evitado usando um método um pouco mais complexo.

    Certamente tem uma variável empacotada em mutex inicializada como false , que o encadeamento define como true a última coisa que ele faz antes de sair. Isso é atômico o suficiente para as suas necessidades?