web-dev-qa-db-fra.com

Comment vérifier si un std :: thread est toujours en cours d'exécution?

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.

70
kispaljr

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.
}
95
Snps

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;
}
5

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);
3
Evgeny Karpov

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.

1
Nathan Fox

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 :)

0
Michal Turlik

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?

0