Ako skontrolovať, či došlo k výnimke v jednom z vlákien?
sobes.tech AI
Odpoveď od AI
Za kontrolu výnimky v vlákne je možné použiť niekoľko prístupov, v závislosti od toho, ako bolo vlákno vytvorené a ako sa spracovávajú jeho výsledky.
-
Použitie
std::futureastd::async: Ak bolo vlákno spustené pomocoustd::async, výsledkom bude objektstd::future. Volaním metódget()alebowait()na tomto objekte spôsobí, že vyvolaná výnimka vo vlákne bude znovu vyhodená vo volajúcom vlákne.#include <future> #include <iostream> #include <stdexcept> void thread_function() { throw std::runtime_error("Chyba vo vlákne!"); } int main() { std::future<void> future = std::async(std::launch::async, thread_function); try { future.get(); // Čaká na dokončenie a hodí výnimku, ak bola } catch (const std::exception& e) { std::cerr << "Výnimka zachytená z vlákna: " << e.what() << std::endl; } return 0; } -
Použitie
std::promiseastd::future: Môže byť explicitne odovzdanéstd::promisedo vlákna alebo ho možno uchovávať mimo neho, aby vlákno mohlo uložiť výnimku.#include <future> #include <iostream> #include <thread> #include <stdexcept> void thread_function_with_promise(std::promise<void>&& promise) { try { throw std::runtime_error("Ešte jedna chyba vo vlákne!"); promise.set_value(); // Nastaví hodnotu (ak nebola výnimka) } catch (...) { promise.set_exception(std::current_exception()); // Uloží výnimku } } 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(); // Čaká na dokončenie a hodí uloženú výnimku } catch (const std::exception& e) { std::cerr << "Výnimka zachytená z vlákna (pomocou promise): " << e.what() << std::endl; } t.join(); // Čaká na dokončenie vlákna return 0; } -
Ručné riadenie výnimiek: Vlákno môže zachytiť výnimku vo vnútri seba a uložiť ju (napríklad v
std::exception_ptr) alebo oznámiť iné vlákno o jej výskyte (napríklad cez atomickú premennú alebo mutex s podmienkovou premennou).#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 v vlákne!"); } catch (...) { std::lock_guard<std::mutex> lock(exception_mutex); global_exception_ptr = std::current_exception(); // Uložiť aktuálne výnimku exception_occurred = true; exception_cv.notify_one(); // Oznámiť čakajúce vlákno } } int main() { std::thread t(thread_function_manual); // Hlavné vlákno môže čakať na oznámenie o výnimke 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); // Znovu vyhodiť uloženú výnimku } catch (const std::exception& e) { std::cerr << "Výnimka zachytená z vlákna (ručné riadenie): " << e.what() << std::endl; } } t.join(); return 0; }
Voľba metódy závisí od kontextu: std::async s std::future je najpohodlnejší na získanie výsledku alebo výnimky z samostatnej úlohy, zatiaľ čo std::promise/std::future alebo ručné riadenie môžu byť užitočné v zložitejších scenároch synchronizácie.