Πώς να ελέγξετε αν συνέβη εξαίρεση σε ένα από τα νήματα;
Απάντηση από AI
sobes.tech AI
Για τον έλεγχο εξαίρεσης σε ένα νήμα, μπορούν να χρησιμοποιηθούν διάφορες προσεγγίσεις, ανάλογα με το πώς δημιουργήθηκε το νήμα και πώς επεξεργάζονται τα αποτελέσματά του.
-
Χρήση
std::futureκαιstd::async: Αν το νήμα ξεκίνησε με τη βοήθεια τουstd::async, το αποτέλεσμα θα είναι ένα αντικείμενοstd::future. Η κλήση των μεθόδωνget()ήwait()σε αυτό το αντικείμενο θα οδηγήσει στην επανεκτόξευση της εξαίρεσης που ρίχτηκε στο νήμα.#include <future> #include <iostream> #include <stdexcept> void thread_function() { throw std::runtime_error("Σφάλμα στο νήμα!"); } int main() { std::future<void> future = std::async(std::launch::async, thread_function); try { future.get(); // Περιμένει την ολοκλήρωση και ρίχνει την εξαίρεση αν υπήρχε } catch (const std::exception& e) { std::cerr << "Εξαίρεση που πιάστηκε από το νήμα: " << e.what() << std::endl; } return 0; } -
Χρήση
std::promiseκαιstd::future: Μπορεί να περάσει ρητά έναstd::promiseστο νήμα ή να το διατηρεί εκτός του νήματος ώστε το νήμα να μπορεί να αποθηκεύσει την εξαίρεση.#include <future> #include <iostream> #include <thread> #include <stdexcept> void thread_function_with_promise(std::promise<void>&& promise) { try { throw std::runtime_error("Άλλο ένα σφάλμα στο νήμα!"); promise.set_value(); // Ορίζει την τιμή (αν δεν υπήρχε εξαίρεση) } catch (...) { promise.set_exception(std::current_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(); // Περιμένει την ολοκλήρωση και ρίχνει την αποθηκευμένη εξαίρεση } catch (const std::exception& e) { std::cerr << "Εξαίρεση που πιάστηκε από το νήμα (με τη βοήθεια promise): " << e.what() << std::endl; } t.join(); // Περιμένει το νήμα να ολοκληρωθεί return 0; } -
Χειρισμός εξαίρεσης χειροκίνητα: Το νήμα μπορεί να πιάσει την εξαίρεση μέσα του και να την αποθηκεύσει (π.χ., σε
std::exception_ptr) ή να ειδοποιήσει κάποιο άλλο νήμα για την εμφάνισή της (π.χ., μέσω ατομικής μεταβλητής ή mutex με μεταβλητή συνθήκης).#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("Λογικό σφάλμα στο νήμα!"); } catch (...) { std::lock_guard<std::mutex> lock(exception_mutex); global_exception_ptr = std::current_exception(); // Αποθηκεύει την τρέχουσα εξαίρεση exception_occurred = true; exception_cv.notify_one(); // Ειδοποιεί το αναμένον νήμα } } int main() { std::thread t(thread_function_manual); // Το κύριο νήμα μπορεί να περιμένει ειδοποίηση για την εξαίρεση 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); // Επαναρίχνει την αποθηκευμένη εξαίρεση } catch (const std::exception& e) { std::cerr << "Εξαίρεση που πιάστηκε από το νήμα (χειροκίνητος χειρισμός): " << e.what() << std::endl; } } t.join(); return 0; }
Η επιλογή της μεθόδου εξαρτάται από το πλαίσιο: το std::async με std::future είναι πιο βολικό για την απόκτηση αποτελέσματος ή εξαίρεσης από μια ξεχωριστή εργασία, ενώ το std::promise/std::future ή ο χειροκίνητος χειρισμός μπορεί να είναι χρήσιμοι σε πιο πολύπλοκα σενάρια συγχρονισμού.