首先,您不需要将bind 与thread 一起使用。这样做只会增加不必要的复制并使代码更难阅读。我希望每个人都不要这样做。
WorkerThread::WorkerThread(){
m_thread = boost::thread(&WorkerThread::drawThread, this);
}
您可以将异常存储在 exception_ptr 中并将其传递给另一个线程,例如在std::queue<std::exception_ptr>:
void WorkerThread::drawThread()
{
while(true)
{
boost::unique_lock<boost::mutex> lock(m_mutex);
try{
///some work is done here...
}catch(std::exception &e){
m_queue.push(std::current_exception());
}
}
}
std::exception_ptr WorkerThread::last_exception()
{
boost::lock_guard<boost::mutex> lock(m_mutex);
std::exception_ptr e;
if (!m_queue.empty())
{
e = m_queue.front();
m_queue.pop();
}
return e;
}
然后在另一个线程中重新抛出并处理它:
if (auto ep = workerThread.last_exception())
{
// do something with exception
try
{
std::rethrow_exception(ep);
}
catch (const std::exception& e)
{
std::cerr << "Error in worker thread: " << e.what() << '\n';
}
}
如果你不能使用std::exception_ptr Boost 有它自己的实现,但我不确定current_exception 的Boost 等价物是什么。您可能需要将异常包装在另一个对象中,以便 Boost 异常传播机制可以存储它。
您可能希望对主工作循环中的异常队列使用单独的互斥锁(并将m_mutex 锁移动到try 块内),具体取决于工作线程通常锁定m_mutex 的时间长短。
另一种方法使用 C++11 期货,它更方便地处理线程之间的异常传递。您需要一些方法让主线程获得工作线程运行的每个工作单元的未来,这可以通过std::packaged_task 完成:
class WorkerThread
{
public:
WorkerThread(); // start m_thread, as before
template<typename F, typename... Args>
std::future<void> post(F f, Args&&... args)
{
Task task(std::bind<void>(f, std::forward<Args>(args)...));
auto fut = task.get_future();
std::lock_guard<std::mutex> lock(m_mutex);
m_tasks.push(std::move(task));
return fut;
}
private:
void drawThread();
std::mutex m_mutex;
using Task = std::packaged_task<void()>;
std::queue<Task> m_tasks;
std::thread m_thread;
};
void WorkerThread::drawThread()
{
Task task;
while(true)
{
{
std::lock_guard<std::mutex> lock(m_mutex);
task = std::move(m_tasks.front());
m_tasks.pop();
}
task(); // run the task
}
}
当任务运行时,任何异常都将被捕获,存储在exception_ptr 中并一直保存到通过关联的未来读取结果。
// other thread:
auto fut = workerThread.post(&someDrawingFunc, arg1, arg2);
...
// check future for errors
try {
fut.get();
} catch (const std::exception& e) {
// handle it
}
生产者线程可以在向消费者发布工作时将future对象存储在队列中,并且其他一些代码可以检查队列中的每个未来以查看它是否准备好并调用get()来处理任何异常.