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 timed_join()
méthode 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 try_lock()
méthode du mutex pour déterminer s'il est toujours verrouillé (le thread est en cours d'exécution), mais cela me semble inutilement complexe.
Connaissez-vous une méthode plus élégante?
Mise à jour: pour être clair: je veux vérifier si le thread s'est correctement terminé ou non. Un fil «suspendu» est considéré comme en cours d'exécution à cet effet.
c++
multithreading
c++11
stdthread
kispaljr
la source
la source
wait()
et, si c'est le cas, si vous ne l'avez paswait()
encore fait, il doit fonctionner par définition. Mais ce raisonnement pourrait être inexact.Réponses:
Si vous êtes prêt à utiliser C ++ 11
std::async
etstd::future
à exécuter vos tâches, vous pouvez utiliser lawait_for
fonction destd::future
pour vérifier si le thread fonctionne toujours d'une manière soignée comme celle-ci:#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
vous pouvez utiliserstd::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 donneront:
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 pourrait ê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. }
Éditer:
Il y a aussi la
std::packaged_task
possibilité d'utiliserstd::thread
pour une solution plus propre que d'utiliserstd::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. }
la source
std::atomic<bool> done(false);
? N'est-ce pas l'bool
atome par défaut?std::atomic
.sizeof(bool)
est définie par l'implémentation et peut être> 1, il est donc possible qu'une écriture partielle se produise. Il y a aussi la question de la cohérence du cache.Une solution simple consiste à avoir une variable booléenne que le thread définit sur true à intervalles réguliers, et qui est vérifiée et définie sur false par le thread qui souhaite connaître l'état. Si la variable est fausse pendant trop longtemps, le thread n'est plus considéré comme actif.
Un moyen plus sûr pour les threads consiste à avoir un compteur qui est augmenté par le thread enfant, et le thread principal compare le compteur à une valeur stockée et si la même chose après trop longtemps, 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 réellement un thread qui s'est bloqué.
Edit Comment vérifier si un thread s'est correctement arrêté 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 elle est vraie, effectuer une jointure sur le thread enfant sans trop de blocage (le cas échéant).
Edit2 Si le thread se termine en raison d'une exception, alors avoir deux fonctions de thread "principales": La première a un
try
- à l'catch
intérieur duquel il appelle la deuxième fonction de thread principal "réelle". 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; }
la source
thread_done
, ce code est interrompu sans barrière de mémoire. Utilisezstd::atomic<bool>
plutôt.bool
pendant que le thread principal en lit - cela nécessite une barrière de mémoire.std::atomic<bool>
est nécessaire ici.Ce mécanisme simple que vous pouvez utiliser pour détecter la finition d'un thread sans bloquer dans la méthode de jointure.
std::thread thread([&thread]() { sleep(3); thread.detach(); }); while(thread.joinable()) sleep(1);
la source
join()
depuis un thread qui n'attend pas que le thread perde sajoinable()
propriété, sinon il bouclera sans fin (c'est-à-direjoinable()
retourne true jusqu'à ce que le thread soit réellementjoin()
ed et pas jusqu'à ce qu'il soit terminé)thread.detach()
pièce, le programme ci-dessus ne se terminera jamais.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 lorsqu'il se termine, il 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 qui est le statut du thread. (Assurez-vous simplement de déverrouiller le mutex si le try_lock a fonctionné)
Un petit problème avec ceci, mutex.try_lock () retournera false entre le moment où le thread est créé et quand il verrouille le mutex, mais cela peut être évité en utilisant une méthode légèrement plus complexe.
la source
std::mutex
pour ce type de signalisation (principalement en raison de la manière dont le mutex est généralement implémenté). Unatomic_flag
fonctionne aussi bien dans ce cas avec beaucoup moins de frais généraux. Astd::future
pourrait être encore mieux car il exprime plus clairement l'intention. De plus, rappelez-vous que celatry_lock
peut échouer faussement, donc le retour n'est pas nécessairement le statut du thread (bien que cela ne vous nuira probablement pas beaucoup dans ce cas particulier).Vous pouvez toujours vérifier si l'id du thread est différent de la construction par défaut de std :: thread :: id (). Un thread en cours d'exécution a toujours un véritable identifiant associé. Essayez d'éviter trop de trucs fantaisistes :)
la source
Avoir sûrement une variable enveloppée de mutex initialisée sur
false
, que le thread définittrue
comme la dernière chose qu'il fait avant de quitter. Est-ce assez atomique pour vos besoins?la source
std::atomic<bool>
s'occupe de cela pour vous, c'est pourquoi c'est la vraie réponse IMO.