Jak zkontrolovat, zda došlo k výjimce v jednom z vláken?
sobes.tech AI
Odpověď od AI
Pro kontrolu výjimky v vlákně lze použít několik přístupů, v závislosti na tom, jak bylo vlákno vytvořeno a jak jsou zpracovávány jeho výsledky.
-
Použití
std::futureastd::async: Pokud bylo vlákno spuštěno pomocístd::async, výsledkem bude objektstd::future. Volání metodget()nebowait()na tomto objektu způsobí, že vyvolaná výjimka ve vlákně bude znovu vyhozena ve volajícím vlákně.#include <future> #include <iostream> #include <stdexcept> void thread_function() { throw std::runtime_error("Chyba ve vlákně!"); } int main() { std::future<void> future = std::async(std::launch::async, thread_function); try { future.get(); // Čeká na dokončení a vyhodí výjimku, pokud byla } catch (const std::exception& e) { std::cerr << "Výjimka zachycena z vlákna: " << e.what() << std::endl; } return 0; } -
Použití
std::promiseastd::future: Může být explicitně předánostd::promisedo vlákna nebo jej lze uchovávat mimo vlákno, aby vlákno mohlo uložit výjimku.#include <future> #include <iostream> #include <thread> #include <stdexcept> void thread_function_with_promise(std::promise<void>&& promise) { try { throw std::runtime_error("Ještě jedna chyba ve vlákně!"); promise.set_value(); // Nastavit hodnotu (kdyby nebyla výjimka) } catch (...) { promise.set_exception(std::current_exception()); // Uložit výjimku } } 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(); // Čeká na dokončení a vyhodí uloženou výjimku } catch (const std::exception& e) { std::cerr << "Výjimka zachycena z vlákna (pomocí promise): " << e.what() << std::endl; } t.join(); // Čeká na dokončení vlákna return 0; } -
Ruční řízení výjimek: Vlákno může zachytit výjimku uvnitř sebe a uložit ji (například v
std::exception_ptr) nebo informovat jiné vlákno o jejím výskytu (například přes atomickou proměnnou nebo mutex s podmínkovou proměnnou).#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("Logická chyba ve vlákně!"); } catch (...) { std::lock_guard<std::mutex> lock(exception_mutex); global_exception_ptr = std::current_exception(); // Uložit aktuální výjimku exception_occurred = true; exception_cv.notify_one(); // Oznámit čekající vlákno } } int main() { std::thread t(thread_function_manual); // Hlavní vlákno může čekat na oznámení o výjimce 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); // Přehodit uloženou výjimku } catch (const std::exception& e) { std::cerr << "Výjimka zachycena z vlákna (ruční řízení): " << e.what() << std::endl; } } t.join(); return 0; }
Volba metody závisí na kontextu: std::async s std::future je nejpohodlnější pro získání výsledku nebo výjimky z samostatného úkolu, zatímco std::promise/std::future nebo ruční řízení může být užitečné v složitějších scénářích synchronizace.