¿Cómo puedo comprobar si std::thread
todavía se está ejecutando (de forma independiente de la plataforma)? Carece de un timed_join()
método y joinable()
no es para eso.
Pensé en bloquear un mutex con un std::lock_guard
en el hilo y usar el try_lock()
método del mutex para determinar si todavía está bloqueado (el hilo se está ejecutando), pero me parece innecesariamente complejo.
¿Conoces un método más elegante?
Actualización: Para ser claro: quiero verificar si el hilo salió limpiamente o no. Un hilo 'colgante' se considera en ejecución para este propósito.
c++
multithreading
c++11
stdthread
kispaljr
fuente
fuente
wait()
y, de ser así, si aún nowait()
lo has hecho, debe estar ejecutándose por definición. Pero este razonamiento puede ser inexacto.Respuestas:
Si está dispuesto a utilizar C ++ 11
std::async
ystd::future
ejecutar sus tareas, puede utilizar lawait_for
función destd::future
para verificar si el hilo todavía se está ejecutando de una manera ordenada como esta:#include <future> #include <thread> #include <chrono> #include <iostream> 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. }
Si debe usar
std::thread
, puede usarstd::promise
para obtener un objeto futuro:#include <future> #include <thread> #include <chrono> #include <iostream> int main() { using namespace std::chrono_literals; // Create a promise and get its future. std::promise<bool> 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 ejemplos darán como resultado:
Por supuesto, esto se debe a que el estado del hilo se comprueba antes de que finalice la tarea.
Pero, de nuevo, podría ser más sencillo hacerlo como otros ya han mencionado:
#include <thread> #include <atomic> #include <chrono> #include <iostream> int main() { using namespace std::chrono_literals; std::atomic<bool> 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:
También existe la opción
std::packaged_task
de usarstd::thread
para una solución más limpia que usarstd::promise
:#include <future> #include <thread> #include <chrono> #include <iostream> int main() { using namespace std::chrono_literals; // Create a packaged_task using some task and get its future. std::packaged_task<void()> 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. }
fuente
std::atomic<bool> done(false);
? ¿No es elbool
atómico por defecto?std::atomic
.sizeof(bool)
está definida por la implementación y puede ser> 1, por lo que es posible que se produzca una escritura parcial. También está el problema de la coherencia de la caché ...Una solución fácil es tener una variable booleana que el subproceso establezca en verdadero en intervalos regulares, y que el subproceso que desee saber el estado verifique y establezca en falso. Si la variable es falsa durante demasiado tiempo, el hilo ya no se considera activo.
Una forma más segura de subprocesos es tener un contador que aumenta con el subproceso secundario, y el subproceso principal compara el contador con un valor almacenado y, si es el mismo después de demasiado tiempo, el subproceso secundario se considera no activo.
Sin embargo, tenga en cuenta que en C ++ 11 no hay forma de matar o eliminar un hilo que se ha colgado.
Editar Cómo comprobar si un hilo ha salido limpiamente o no: Básicamente, la misma técnica que se describe en el primer párrafo; Tener una variable booleana inicializada en falso. Lo último que hace el subproceso secundario es establecerlo en verdadero. El hilo principal puede verificar esa variable y, si es verdadero, hacer una unión en el hilo secundario sin mucho (si lo hay) bloqueo.
Edit2 Si el hilo sale debido a una excepción, entonces tenga dos funciones "principales" del hilo: La primera tiene un
try
-catch
dentro del cual llama a la segunda función del hilo principal "real". Esta primera función principal establece la variable "have_exited". Algo como esto:bool thread_done = false; void *thread_function(void *arg) { void *res = nullptr; try { res = real_thread_function(arg); } catch (...) { } thread_done = true; return res; }
fuente
thread_done
, este código se rompe sin una barrera de memoria. Úselo en sustd::atomic<bool>
lugar.bool
mientras el subproceso principal lee de él; esto necesita una barrera de memoria.std::atomic<bool>
es necesario aquí.Este sencillo mecanismo se puede utilizar para detectar el acabado de un hilo sin bloquear el método de unión.
std::thread thread([&thread]() { sleep(3); thread.detach(); }); while(thread.joinable()) sleep(1);
fuente
join()
desde algún hilo que no espere a que el hilo pierda sujoinable()
propiedad, de lo contrario, se repetirá sin fin (es decir,joinable()
regresará verdadero hasta que el hilo sea realmentejoin()
ed y no hasta que esté terminado)thread.detach()
pieza, el programa anterior nunca terminará.Cree un mutex al que tengan acceso el hilo en ejecución y el hilo que llama. Cuando se inicia el subproceso en ejecución, bloquea el mutex, y cuando termina, lo desbloquea. Para comprobar si el hilo aún se está ejecutando, el hilo de llamada llama a mutex.try_lock (). El valor de retorno de eso es el estado del hilo. (Solo asegúrese de desbloquear el mutex si el try_lock funcionó)
Un pequeño problema con esto, mutex.try_lock () devolverá falso entre el momento en que se crea el hilo y cuando bloquea el mutex, pero esto se puede evitar usando un método un poco más complejo.
fuente
std::mutex
para este tipo de señalización (principalmente debido a las razones por las que generalmente se implementa mutex). Unatomic_flag
funciona igual de bien en este caso con menos gastos generales. Astd::future
podría ser incluso mejor ya que expresa la intención con mayor claridad. Además, recuerde quetry_lock
puede fallar de manera falsa, por lo que la devolución no es necesariamente el estado del hilo (aunque probablemente no le hará mucho daño en este caso particular).Siempre puede verificar si la identificación del hilo es diferente a std :: thread :: id () construido por defecto. Un hilo en ejecución siempre tiene un ID asociado genuino. Intenta evitar demasiadas cosas elegantes :)
fuente
Seguramente tenga una variable envuelta en mutex inicializada en
false
, que el hilo establecetrue
como lo último que hace antes de salir. ¿Es eso lo suficientemente atómico para sus necesidades?fuente
std::atomic<bool>
se encarga de esto por usted, por lo que es la verdadera respuesta en mi opinión.