Назад к вопросам
Middle+
81
questionbank

Как проверить, произошло ли исключение в одном из потоков?

Sobes Copilot

Получайте ответы в реальном времени

Ответ от нейросети

sobes.tech AI

Есть несколько способов:

  1. Future и std::async: std::async возвращает std::future. При попытке получить результат из future (например, с помощью future.get()) в главном потоке, если в асинхронной задаче произошло исключение, оно будет повторно брошено в главном потоке.
  2. std::promise и std::future: Поток, в котором может возникнуть исключение, может "захватить" исключение и сохранить его в std::promise с помощью promise.set_exception(). Другой поток может получить(promise.get_future()) соответствующий std::future и при вызове future.get() получить сохраненное исключение.
  3. try-catch внутри потока и передача статуса: Внутри потока обернуть потенциально "опасный" код в try-catch блок. В случае исключения, сохранить указатель на него (с помощью std::current_exception()) или специальный флаг в разделяемой переменной, доступ к которой синхронизирован.
  4. Библиотека 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 предоставляют больше гибкости. Ручное сохранение статуса или исключения подходит для специфических сценариев с кастомной логикой синхронизации.