Sobes.tech
Middle+
314

Comment vérifier si une exception s'est produite dans l'un des threads?

Réponse de l'IA

sobes.tech IA

Pour vérifier les exceptions dans un thread, plusieurs approches peuvent être utilisées en fonction de la façon dont le thread a été créé et de la gestion de ses résultats.

  1. Utilisation de std::future et std::async: Si le thread a été lancé avec std::async, le résultat sera un objet std::future. Appeler les méthodes get() ou wait() sur cet objet entraînera la relance de l'exception levée dans le thread dans le thread appelant.

    #include <future>
    #include <iostream>
    #include <stdexcept>
    
    void thread_function() {
        throw std::runtime_error("Erreur dans le thread!");
    }
    
    int main() {
        std::future<void> future = std::async(std::launch::async, thread_function);
    
        try {
            future.get(); // Attend la fin et relance l'exception si elle existe
        } catch (const std::exception& e) {
            std::cerr << "Exception capturée du thread: " << e.what() << std::endl;
        }
    
        return 0;
    }
    
  2. Utilisation de std::promise et std::future: Il est possible de passer explicitement un std::promise au thread ou de le garder en dehors pour que le thread puisse sauvegarder l'exception.

    #include <future>
    #include <iostream>
    #include <thread>
    #include <stdexcept>
    
    void thread_function_with_promise(std::promise<void>&& promise) {
        try {
            throw std::runtime_error("Une autre erreur dans le thread!");
            promise.set_value(); // Définir la valeur (si pas d'exception)
        } catch (...) {
            promise.set_exception(std::current_exception()); // Sauvegarder l'exception
        }
    }
    
    int main() {
        std::promise<void> promise;
        std::future<void> future = promise.get_future();
    
        std::thread t(thread_function_with_promise, std::move(promise));
    
        try {
            future.get(); // Attend la fin et relance l'exception sauvegardée
        } catch (const std::exception& e) {
            std::cerr << "Exception capturée du thread (avec promise): " << e.what() << std::endl;
        }
    
        t.join(); // Attend la fin du thread
    
        return 0;
    }
    
  3. Gestion manuelle des exceptions: Le thread peut attraper l'exception en interne et la sauvegarder (par exemple, dans std::exception_ptr) ou en informer un autre thread (par exemple, via une variable atomique ou un mutex avec une variable conditionnelle).

    #include <iostream>
    #include <thread>
    #include <atomic>
    #include <exception>
    #include <mutex>
    #include <condition_variable>
    
    std::exception_ptr global_exception_ptr = nullptr;
    std::mutex exception_mutex;
    std::condition_variable exception_cv;
    bool exception_occurred = false;
    
    void thread_function_manual() {
        try {
            throw std::logic_error("Erreur logique dans le thread!");
        } catch (...) {
            std::lock_guard<std::mutex> lock(exception_mutex);
            global_exception_ptr = std::current_exception(); // Sauvegarder l'exception courante
            exception_occurred = true;
            exception_cv.notify_one(); // Notifier le thread en attente
        }
    }
    
    int main() {
        std::thread t(thread_function_manual);
    
        // Le thread principal peut attendre la notification de l'exception
        std::unique_lock<std::mutex> lock(exception_mutex);
        exception_cv.wait(lock, []{ return exception_occurred; });
    
        if (global_exception_ptr) {
            try {
                std::rethrow_exception(global_exception_ptr); // Relancer l'exception sauvegardée
            } catch (const std::exception& e) {
                std::cerr << "Exception capturée du thread (gestion manuelle): " << e.what() << std::endl;
            }
        }
    
        t.join();
    
        return 0;
    }
    

Le choix de la méthode dépend du contexte : std::async avec std::future est le plus pratique pour obtenir un résultat ou une exception d'une tâche séparée, tandis que std::promise/std::future ou la gestion manuelle peuvent être utiles dans des scénarios de synchronisation plus complexes.