#include <iostream>
#include <thread>
#include <vector>
#include <mutex>
#include <stdexcept>
class MyClass {
public:
void run() {
// do some work
}
struct Data {
double x{0.0};
int y{0};
} data;
};
void Thread_function(int i, MyClass myclass, std::exception_ptr &exc, std::mutex &mtx)
{
try {
// Modify some of the struct parameters
auto dataCopy = myclass.data;
dataCopy.x = i + 1;
dataCopy.y = (i + 1) * 0.5;
// run the simulation with changed parameters
myclass.data = dataCopy;
myclass.run();
}
catch (const std::exception &exception)
{
// lock capturedException
std::lock_guard<std::mutex> lock(mtx);
exc = std::current_exception();
}
}
int main() {
const int num_threads = 5;
std::vector<std::thread> threads;
std::exception_ptr capturedException;
std::mutex mtx;
MyClass myClass;
// create threads
for (int i = 0; i < num_threads; ++i)
{
threads.emplace_back(
Thread_function, i, myClass, std::ref(capturedException), std::ref(mtx));
}
// wait for all threads to finish
for (auto& t : threads)
{
t.join();
}
// main thread rethrows exception, if any
if (capturedException)
{
throw capturedException;
return 1;
}
return 0;
}
在主函数中创建了几个线程,这些线程在
run
函数中执行一些计算。在线程函数中,我使用try/catch
块来捕获异常,并使用std::lock_guard<std::mutex> for synchronization
,因为exc
是所有线程之间的共享变量(通过引用传递)。
在主函数中,我等待所有线程加入,然后从线程中重新抛出异常。
但是,在 main 中,一旦线程抛出异常,我想
return 1
。无需等待其他线程。目前,m̀ain
等待所有线程完成,尽管其中一个线程可能已经抛出异常。
我怎样才能解决这个问题? C++ 库中有类可以顺利处理这个问题吗?
让我为您画一个替代代码的示例:
#include <iostream>
#include <thread>
#include <mutex>
#include <stdexcept>
#include <condition_variable>
#include <cassert>
class MyClass {
public:
void run() {
// do some work
}
struct Data {
double x{0.0};
int y{0};
} data;
};
void Thread_function(int i, MyClass myclass)
{
// if (i==3) throw std::runtime_error("boo!");
// Modify some of the struct parameters
auto dataCopy = myclass.data;
dataCopy.x = i + 1;
dataCopy.y = (i + 1) * 0.5;
// run the simulation with changed parameters
myclass.data = dataCopy;
myclass.run();
}
int main() {
const int num_threads = 5;
MyClass myClass;
struct Tracking
{
std::mutex mutex;
std::condition_variable condition;
unsigned int counter=0;
std::exception_ptr capturedException;
} tracking;
// create threads
for (int i = 0; i < num_threads; ++i)
{
{
std::lock_guard<decltype(tracking.mutex)> lock(tracking.mutex);
tracking.counter++;
}
std::thread([&tracking, i](){
try
{
Thread_function(i, MyClass());
}
catch(const std::exception &exception)
{
std::lock_guard<decltype(tracking.mutex)> lock(tracking.mutex);
std::cout << "thread " << i << " exception\n";
if (!tracking.capturedException)
{
tracking.capturedException=std::current_exception();
}
}
{
std::lock_guard<decltype(tracking.mutex)> lock(tracking.mutex);
tracking.counter--;
std::cout << "thread " << i << " exit\n";
}
tracking.condition.notify_all();
}).detach();
}
// wait for all threads to finish, or an exception to appear
std::unique_lock<decltype(tracking.mutex)> lock(tracking.mutex);
tracking.condition.wait(lock, [&tracking]() { return tracking.counter==0 || tracking.capturedException; });
// main thread rethrows exception, if any
if (tracking.capturedException)
{
try
{
std::rethrow_exception(tracking.capturedException);
}
catch(const std::exception& exception)
{
std::cerr << exception.what() << "\n";
return EXIT_FAILURE;
}
}
assert(tracking.counter==0);
return 0;
}
我基本上坚持你的结构,但让我指出一些变化。
创建线程时,我在
Thread_Function
周围放置了一个包装器,用于处理与主线程的通信。主线程计算它创建的线程数量,而包装器代码会在线程退出时减少计数。条件变量用于告诉主线程某些内容发生了变化。
主线程等待计数达到 0,或出现异常。
另外,与您的代码不同,我只是在主线程上打印异常。没有必要把它重新扔在那里。