Comment puis-je vérifier si un std::thread
Est toujours en cours d'exécution (de manière indépendante de la plate-forme)? Il manque une méthode timed_join()
et joinable()
n'est pas fait pour cela.
J'ai pensé verrouiller un mutex avec un std::lock_guard
Dans le thread et utiliser la méthode try_lock()
du mutex pour déterminer s'il est toujours verrouillé (le thread est en cours d'exécution), mais cela semble inutilement complexe pour moi.
Connaissez-vous une méthode plus élégante?
Mise à jour: Pour être clair: je veux vérifier si le thread est sorti correctement ou non. Un fil "suspendu" est considéré comme étant en cours d'exécution à cette fin.
Si vous souhaitez utiliser C++ 11 std::async
et std::future
pour exécuter vos tâches, vous pouvez utiliser le wait_for
fonction de std::future
pour vérifier si le thread est toujours en cours d'exécution d'une manière ordonnée comme ceci:
#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 vous devez utiliser std::thread
alors vous pouvez utiliser std::promise
pour obtenir un futur objet:
#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.
}
Ces deux exemples produiront:
Thread still running
C'est bien sûr parce que l'état du thread est vérifié avant la fin de la tâche.
Mais là encore, il serait peut-être plus simple de le faire comme d'autres l'ont déjà mentionné:
#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.
}
Edit:
Il y a aussi le std::packaged_task
A utiliser avec std::thread
pour une solution plus propre que d'utiliser std::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.
}
Une solution simple consiste à définir une variable booléenne définie par le thread sur true à intervalles réguliers. Cette variable est vérifiée et définie sur false par le thread qui souhaite connaître le statut. Si la variable est false pendant trop longtemps, le thread n'est plus considéré comme actif.
Un moyen plus sûr pour les threads est d'avoir un compteur augmenté par le thread enfant et le thread principal le compare à une valeur stockée. S'il est identique après un temps trop long, le thread enfant est considéré comme inactif.
Notez cependant qu'il n'y a aucun moyen dans C++ 11 de tuer ou de supprimer un thread qui a été suspendu.
Edit Comment vérifier si un thread est sorti correctement ou non: Fondamentalement, la même technique que celle décrite dans le premier paragraphe; Avoir une variable booléenne initialisée à false. La dernière chose que fait le thread enfant est de le définir sur true. Le thread principal peut alors vérifier cette variable et, si true, effectue une jointure sur le thread enfant sans bloquer (le cas échéant).
Edit2 Si le thread se ferme en raison d'une exception, il comporte deux fonctions "principales" de thread: le premier a un try
-catch
à l'intérieur duquel il appelle le second "réel" fonction du fil principal. Cette première fonction principale définit la variable "have_exited". Quelque chose comme ça:
bool thread_done = false;
void *thread_function(void *arg)
{
void *res = nullptr;
try
{
res = real_thread_function(arg);
}
catch (...)
{
}
thread_done = true;
return res;
}
Ce mécanisme simple que vous pouvez utiliser pour détecter la finition d'un thread sans bloquer la méthode de jointure.
std::thread thread([&thread]() {
sleep(3);
thread.detach();
});
while(thread.joinable())
sleep(1);
Créez un mutex auquel le thread en cours d'exécution et le thread appelant ont tous deux accès. Lorsque le thread en cours d'exécution démarre, il verrouille le mutex et, à la fin, déverrouille le mutex. Pour vérifier si le thread est toujours en cours d'exécution, le thread appelant appelle mutex.try_lock (). La valeur de retour de cela est le statut du thread. (Assurez-vous simplement de déverrouiller le mutex si le try_lock a fonctionné)
Un petit problème avec cela, mutex.try_lock () retournera false entre le moment où le thread est créé et celui où il verrouille le mutex, mais ceci peut être évité en utilisant une méthode légèrement plus complexe.
Vous pouvez toujours vérifier si l'id du thread est différent de std :: thread :: id () par défaut. Un thread en cours d'exécution a toujours un identifiant associé authentique. Essayez d'éviter trop de choses fantaisistes :)
Ayez sûrement une variable mutex-wrapped initialisée à false
, que le thread définit à true
comme la dernière chose à faire avant de quitter. Est-ce assez atomique pour vos besoins?