Sobes.tech
Middle+
315

Πώς να ελέγξετε αν συνέβη εξαίρεση σε ένα από τα νήματα;

Απάντηση από AI

sobes.tech AI

Για τον έλεγχο εξαίρεσης σε ένα νήμα, μπορούν να χρησιμοποιηθούν διάφορες προσεγγίσεις, ανάλογα με το πώς δημιουργήθηκε το νήμα και πώς επεξεργάζονται τα αποτελέσματά του.

  1. Χρήση 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;
    }
    
  2. Χρήση 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;
    }
    
  3. Χειρισμός εξαίρεσης χειροκίνητα: Το νήμα μπορεί να πιάσει την εξαίρεση μέσα του και να την αποθηκεύσει (π.χ., σε 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 ή ο χειροκίνητος χειρισμός μπορεί να είναι χρήσιμοι σε πιο πολύπλοκα σενάρια συγχρονισμού.