Sobes.tech
Middle+
316

Как да проверите дали е възникнало изключение в един от нишките?

Отговор от 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) или да уведоми друга нишка за неговото възникване (например, чрез атомарна променлива или мьютекс с условна променлива).

    #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 или ръчно управление могат да бъдат полезни в по-сложни сценарии за синхронизация.