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++ 예외만 잡아서 프로그램을 터트리기 때문이다.