基本上,我有一种情况,一个线程抛出异常,而另一个线程需要处理。我试图用boost异常来做这个,但是在这个行的某个地方,异常会丢失它的类型,因此不会被catch块捕获。
基本上,线程B想做某事,但由于各种原因必须用线程A完成(如果你想知道这些原因,请问MS为什么必须创建一个direct3d 9设备,由同一个线程重置和释放创建了窗口)。如果在执行这些操作时发生异常,则线程A捕获它,将其传递回线程B,线程B然后重新抛出它以根据需要进行处理。问题是线程B中抛出的异常似乎与线程A中抛出的异常不同:(
我程序的调试输出,代码如下。
First-chance exception at 0x776b42eb ...: fllib::exception::Error at memory location 0x0019e590.. First-chance exception at 0x776b42eb ...: [rethrow] at memory location 0x00000000.. First-chance exception at 0x776b42eb ...: boost::exception_detail::clone_impl<boost::unknown_exception> at memory location 0x0019eed4..
//thread B
...
try
{
SendCallback(hwnd, boost::bind(&Graphics::create, this));
}
catch(fllib::exception::Error &except)//example catch block, doesnt catch example exception
{
...handle exception...
}
void SendCallback(HWND hwnd, boost::function<void()> call)
{
boost::exception_ptr *except_ptr =
(boost::exception_ptr*)SendMessage(hwnd, WM_CALLBACK, (unsigned)&call, SEND);
if(except_ptr)//if an exception occurred, throw it in thread B's context
{
boost::exception_ptr except = *except_ptr;
delete except_ptr;
boost::rethrow_exception(except);
}
}
//thread A
LRESULT CALLBACK HookProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
//check for our custom message
if(msg == WM_CALLBACK)
{
if(lParam == POST)
{
...
}
else
{
boost::function<void()> *call = (boost::function<void()>*)wParam;
try
{
(*call)();
}
catch(...)
{
return (unsigned)new boost::exception_ptr(boost::current_exception());
}
return 0;
}
}
else
{
...
}
}
void Graphics::create()
{
...code that may throw exceptions...
eg
throw fllib::exception::Error(L"Test Exception...");
}
答案 0 :(得分:2)
确保来自线程A的每次抛出都使用boost :: enable_current_exception包装器。请参阅this。
“除非enable_current_exception是 当时调用异常对象 用于throw-expression,an 尝试使用复制它 current_exception可能会返回一个 exception_ptr,指的是 unknown_exception的实例。“
为此,您可能需要捕获线程A中的所有异常,并在使用throw boost :: enable_current_exception(your_exception)包装它们之后重新抛出它们。
此外,除非您使用_set_se_translator来调用包装器并将它们包装在异常对象中,否则这对于除零等结构化异常不起作用。
答案 1 :(得分:1)
我为自己的异常类型找到了解决方案。
Baiscly我为我的所有异常类型添加了2个虚拟方法。
这意味着我现在可以做到:
void SendCallback(HWND hwnd, boost::function<void()> call)
{
fllib::exception::Base *except_ptr =
(fllib::exception::Base*)SendMessage(hwnd, WM_CALLBACK, (unsigned)&call, SEND);
if(except_ptr) except_ptr->ThrowAndDelete();
}
LRESULT CALLBACK HookProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
//check for our custom message
if(msg == WM_CALLBACK)
{
if(lParam == POST)
{
...
}
else
{
boost::function<void()> *call = (boost::function<void()>*)wParam;
try
{
(*call)();
}
catch(fllib::exception::Base &except)
{
return (unsigned)except.Clone();
}
return 0;
}
}
else
{
...
}
}
我不知道如何处理std ::和boost :: varity的异常,因为它们似乎没有上述效果的方法......但95%以上的例外情况并非如此事先处理的是我自己的课程,而那些没有的课程几乎肯定会被处理掉......
答案 2 :(得分:1)
使用BOOST_THROW_EXCEPTION抛出异常。
在线程中,catch(...),然后调用boost :: current_exception将异常(无论它是什么)填充到boost :: exception_ptr中。
将exception_ptr复制到主线程,然后调用rethrow_exception。这将重新抛出捕获(...)线程中捕获的异常对象。
见www.boost.org/doc/libs/release/libs/exception/doc/tutorial_exception_ptr.html。
答案 3 :(得分:0)
我认为你有问题,因为没有用boost方式抛出异常。
你可以在钩子程序中捕获线程A中的concrette异常,将其复制到新对象中,返回指针。
在SendCallback中检查结果,如果结果存在则抛出(不是NULL)
但是如果你没有异常,你应该确保永远返回NULL。