Как проверить, произошло ли исключение в одном из потоков?
Sobes Copilot
Получайте ответы в реальном времени
Ответ от нейросети
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) или уведомить другой поток о его возникновении (например, через атомарную переменную или мьютекс с условной переменной).#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 или ручное управление могут быть полезны в более сложных сценариях синхронизации.