Programming/C++ & Unreal
C++ parallel for_each (thread) exception
장형이
2023. 10. 23. 03:37
#include <iostream>
#include <windows.h>
#include <thread>
#include <execution>
#include <vector>
#include <algorithm>
LONG WINAPI UnhandleExceptionHandler(_EXCEPTION_POINTERS* exceptionInfo) {
std::cout << "Exception catched!"; // 출력되지 않음.
return 0;
}
int main()
{
SetUnhandledExceptionFilter(UnhandleExceptionHandler);
// 쓰레드에서 std::Exception 발생.
std::thread th1([]() { throw std::exception(); });
th1.join();
// parallel for_each에서 std::Exception 발생.
std::vector<int> vec{ 1,2,3 };
std::for_each(std::execution::par_unseq, vec.begin(), vec.end(), [](const int& num) {
throw std::exception();
});
std::cout << "fin."; // 출력되지 않음.
}
thread나 for_each는 기본적으로 noexcept로 작동하기 때문에, C++ exception이 발생하면 std::terminate 된다.
그래서 위 코드에서 예외를 잡을 수 없고 아무런 출력도 발생하지 않는다.
void TerminateHandler() {
std::cout << "Program terminated!"; // 출력됨.
}
int main()
{
// 쓰레드에서 std::Exception 발생.
std::thread th1([]() {
std::set_terminate(TerminateHandler); throw std::exception();
});
th1.join();
// parallel for_each에서 std::Exception 발생.
std::vector<int> vec{ 1,2,3 };
std::for_each(std::execution::par_unseq, vec.begin(), vec.end(), [](const int& num) {
std::set_terminate(TerminateHandler);
throw std::exception();
});
}
그래서 위와 같이 TerminateHandler를 통하여 로그를 남기거나,
Thread,Task 관련 로직에 try_catch를 잘 심어두어야 한다.
LONG WINAPI UnhandleExceptionHandler(_EXCEPTION_POINTERS* exceptionInfo) {
std::cout << "Exception catched!"; // 출력됨.
return 0;
}
int main()
{
SetUnhandledExceptionFilter(UnhandleExceptionHandler);
// 쓰레드에서 SEH Exception 발생.
std::thread th1([]() {
char* a = 0; *a = 5;
});
th1.join();
// parallel for_each에서 SEH Exception 발생.
std::vector<int> vec{ 1,2,3 };
std::for_each(std::execution::par_unseq, vec.begin(), vec.end(), [](const int& num) {
char* a = 0; *a = 5;
});
std::cout << "fin."; // 출력되지 않음.
}
하지만! SEH 예외가 발생하면 UnhandleExceptionHandler를 통해서 잡을 수 있다.
noexcept terminate 로직은 내부적으로 C++ 예외만 잡아서 프로그램을 터트리기 때문이다.