C++ - 스레드 내에서 발생한 예외 처리
참고
아래의 코드는 sigma_reference 함수에서 예외가 발생하는 경우 main에서 catch하고 있지만 예외가 잡히지 않는다.
이유는 sigma_reference 함수의 스레드와 main 함수의 스레드가 서로 다르기 때문이다.
#include <thread>
#include <iostream>
#include <functional> // ref
#include <stdexcept> // invalid_argument
#include <string> // to_string
/*
* n < 0 때 invalid_argument 예외를 throw 한다
*/
void sigma_reference(int n, int& result) {
if ( n < 0 ) {
throw std::invalid_argument(std::to_string(n));
}
int sum = 0;
for ( int i = 0; i <= n; ++i ) {
sum += i;
}
result = sum;
}
int main() {
using namespace std;
int result;
for ( int n : { 5, -3, 10 } ) try {
thread thr(sigma_reference, n, ref(result));
thr.join();
cout << "1+2+...+" << n << "= " << result << endl;
} catch ( invalid_argument& err ) {
cerr << err.what() << endl;
}
}
exception_ptr를 사용하면 위 문제를 해결할 있다.
#include <iostream>
#include <thread>
#include <functional> // ref
#include <stdexcept> // invalid_argument
#include <exception> // current_exception/rethrow_exception
#include <string> // to_string
void sigma_reference(int n, int& result) {
if ( n < 0 ) {
throw std::invalid_argument(std::to_string(n));
}
int sum = 0;
for ( int i = 0; i <= n; ++i ) {
sum += i;
}
result = sum;
}
/*
* sigma_reference 함수를 랩핑한다
*/
void sigma_reference_wrap(int n, int& result, std::exception_ptr& exp) try {
sigma_reference(n, result);
} catch (...) {
// catch 된 예외(가 wrap된 exception_ptr)를 set 한다
exp = std::current_exception();
// 스레드는 이 시점에서 종료한다
}
int main() {
using namespace std;
int result;
for ( int n : { 5, -3, 10 } ) try {
exception_ptr exp;
thread thr(sigma_reference_wrap, n, ref(result), ref(exp));
thr.join();
// 스레드 내에서 예외고 발생하고 있다면 다시 throw
if ( exp ) {
rethrow_exception(exp);
}
cout << "1+2+...+" << n << "= " << result << endl;
} catch ( invalid_argument& err ) { // 다시 throw된 에외를 catch
cerr << err.what() << endl;
}
}
이 글은 2019-11-28에 작성되었습니다.