Назад к вопросам
Middle+
81
questionbank
Как проверить, произошло ли исключение в одном из потоков?
Sobes Copilot
Получайте ответы в реальном времени
Ответ от нейросети
sobes.tech AI
Есть несколько способов:
- Future и std::async:
std::asyncвозвращаетstd::future. При попытке получить результат из future (например, с помощьюfuture.get()) в главном потоке, если в асинхронной задаче произошло исключение, оно будет повторно брошено в главном потоке. - std::promise и std::future: Поток, в котором может возникнуть исключение, может "захватить" исключение и сохранить его в
std::promiseс помощьюpromise.set_exception(). Другой поток может получить(promise.get_future()) соответствующийstd::futureи при вызовеfuture.get()получить сохраненное исключение. - try-catch внутри потока и передача статуса: Внутри потока обернуть потенциально "опасный" код в
try-catchблок. В случае исключения, сохранить указатель на него (с помощьюstd::current_exception()) или специальный флаг в разделяемой переменной, доступ к которой синхронизирован. - Библиотека
boost::exception:boost::exceptionпредоставляет более мощные механизмы для захвата, хранения и передачи исключений между потоками, позволяя прикреплять к исключению дополнительную информацию.
Пример с std::async:
#include <iostream>
#include <future>
#include <thread>
#include <vector>
#include <exception>
// Функция, которая может бросить исключение
int divide(int a, int b) {
if (b == 0) {
throw std::runtime_error("Division by zero!");
}
return a / b;
}
int main() {
// Запускаем задачу асинхронно
std::future<int> fut = std::async(std::launch::async, divide, 10, 0);
try {
// Пытаемся получить результат. Если было исключение, оно бросится здесь.
int result = fut.get();
std::cout << "Result: " << result << std::endl;
} catch (const std::exception& e) {
// Обрабатываем исключение, которое произошло в другом потоке
std::cerr << "Caught exception from thread: " << e.what() << std::endl;
}
return 0;
}
Пример с std::promise и std::future:
#include <iostream>
#include <future>
#include <thread>
#include <exception>
void worker_function(std::promise<int>&& prom) {
try {
// Код, который может бросить исключение
int result = 5 / 0; // Предположим, что здесь может быть ошибка
prom.set_value(result); // Устанавливаем успешное значение
} catch (...) {
// Захватываем текущее исключение
try {
prom.set_exception(std::current_exception()); // Устанавливаем исключение
} catch (...) {
// Произошла ошибка при установке исключения (маловероятно)
}
}
}
int main() {
std::promise<int> prom;
std::future<int> fut = prom.get_future();
// Запускаем поток с worker_function
std::thread t(worker_function, std::move(prom));
try {
// Пытаемся получить результат из future
int result = fut.get();
std::cout << "Result: " << result << std::endl;
} catch (const std::exception& e) {
// Обрабатываем исключение, которое было установлено в promise
std::cerr << "Caught exception from thread: " << e.what() << std::endl;
}
t.join(); // Ждем завершения потока
return 0;
}
Выбор метода зависит от архитектуры приложения и требований к обработке ошибок. std::async и std::future являются наиболее простым способом для передачи результатов и исключений из одноразовых задач. std::promise и std::future предоставляют больше гибкости. Ручное сохранение статуса или исключения подходит для специфических сценариев с кастомной логикой синхронизации.