Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/156.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;:跨线程错误处理问题_C++_Multithreading_Exception_Error Handling - Fatal编程技术网

C++ C++;:跨线程错误处理问题

C++ C++;:跨线程错误处理问题,c++,multithreading,exception,error-handling,C++,Multithreading,Exception,Error Handling,一般来说,我使用异常来处理错误,但是这里的问题是错误应用于不同的线程,而不是导致错误的线程 基本上,窗口有自己的线程,direct3d设备必须由创建窗口的同一线程创建和重置。但是,创建设备可能会失败,因此我需要在尝试创建实例的线程中抛出异常,而不是窗口代码 回调函数: void Callback(HWND hwnd, boost::function<void(HWND,LPARAM)> call, LPARAM lParam) { //Make our stack alloc

一般来说,我使用异常来处理错误,但是这里的问题是错误应用于不同的线程,而不是导致错误的线程

基本上,窗口有自己的线程,direct3d设备必须由创建窗口的同一线程创建和重置。但是,创建设备可能会失败,因此我需要在尝试创建实例的线程中抛出异常,而不是窗口代码

回调函数:

void Callback(HWND hwnd, boost::function<void(HWND,LPARAM)> call, LPARAM lParam)
{
    //Make our stack allocated function object into a heap allocated one
    boost::function<void(HWND,LPARAM)> *callH = new boost::function<void(HWND,LPARAM)>(call);
    //send a message with a pointer to our function object in the WPARAM
    PostMessage(hwnd, WM_CALLBACK, (unsigned)callH, lParam);
}
LRESULT CALLBACK HookProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    //check for our custom message
    if(msg == WM_CALLBACK)
    {
        //retreive the function pointer from the WPARAM
        boost::function<void(HWND,LPARAM)> *callH = (boost::function<void(HWND,LPARAM)>*)wParam;
        //call it
        (*callH)(hwnd,lParam);
        //delete our heap allocated function object
        delete callH;
        return 0;
    }
    else
        //if there was nothing relevant to us, call the old message procedure
        return CallWindowProc(hooked[hwnd], hwnd, msg, wParam, lParam);
}
//std::map<HWND, WNDPROC> hooked;
无效回调(HWND-HWND,boost::函数调用,LPARAM-LPARAM) { //将堆栈分配的函数对象转换为堆分配的函数对象 boost::function*callH=新的boost::function(call); //在WPARAM中发送一条带有指向函数对象指针的消息 PostMessage(hwnd,WM_CALLBACK,(unsigned)callH,lParam); } LRESULT回调HookProc(HWND HWND,UINT msg,WPARAM WPARAM,LPARAM LPARAM) { //检查我们的自定义消息 if(msg==WM\u回调) { //从WPARAM中检索函数指针 boost::function*callH=(boost::function*)wParam; //叫它 (*callH)(hwnd、lParam); //删除堆分配的函数对象 删除callH; 返回0; } 其他的 //如果与我们无关,请调用旧的消息过程 返回CallWindowProc(钩住[hwnd]、hwnd、msg、wParam、lParam); } //标准::地图钩; 请求窗口线程创建设备的代码

Graphics::Graphics(IWindow *_window, Size2<unsigned> _size)
:lost(false), reset(false), refCnt(0), backCol(0xFF000000),
started(false), exited(false),
window(_window), size(_size)
{
    window->AddRef();
    HWND hwnd = *((HWND*)window->GetHandle());
    CallbackHook(hwnd);
    Callback(hwnd, boost::bind(&Graphics::create, this), 0);

    while(!started)Sleep(100);
}
void Graphics::create()
{
...code that may throw various exceptions
    started = true;
}
Graphics::Graphics(IWindow*\u窗口,大小2\u)
:丢失(false)、重置(false)、引用(0)、返回列(0xFF000000),
启动(错误)、退出(错误),
窗口(_窗口),大小(_大小)
{
窗口->添加参考();
HWND HWND=*((HWND*)窗口->获取句柄();
回调钩(hwnd);
回调(hwnd,boost::bind(&Graphics::create,this),0);
当(!开始)睡眠时(100);
}
void Graphics::create()
{
…可能引发各种异常的代码
开始=真;
}

所以基本上我需要create()方法抛出的异常被创建图形对象的异常处理程序捕获,这是另一个线程。

答案是不能。一个可行的替代方法是,只在回调函数中执行不会失败的必要工作,比如从参数中提取值,然后在主线程中调用create()函数

此外,您不应该忙于等待创建、使用信号量或互斥量&事件等

Graphics::Graphics(IWindow *_window, Size2<unsigned> _size)
:lost(false), reset(false), refCnt(0), backCol(0xFF000000),
started(false), exited(false),
window(_window), size(_size)
{
    window->AddRef();
    HWND hwnd = *((HWND*)window->GetHandle());
    semaphore = CreateSemaphore(NULL, 0, 1, NULL);
    if (semaphore == NULL) throw whatever;
    CallbackHook(hwnd);
    Callback(hwnd, boost::bind(&Graphics::create, this), 0);

    WaitForSingleObject(semaphore);
    create();

    CloseHandle(semaphore); /* you won't need it */
}
void Graphics::create()
{
...code that may throw various exceptions
}
void Graphics::create_callback()
{
    ReleaseSemaphore(semaphore, 1, NULL);
}
Graphics::Graphics(IWindow*\u窗口,大小2\u)
:丢失(false)、重置(false)、引用(0)、返回列(0xFF000000),
启动(错误)、退出(错误),
窗口(_窗口),大小(_大小)
{
窗口->添加参考();
HWND HWND=*((HWND*)窗口->获取句柄();
信号量=CreateSemaphore(NULL,0,1,NULL);
如果(信号量==NULL)抛出任何内容;
回调钩(hwnd);
回调(hwnd,boost::bind(&Graphics::create,this),0);
WaitForSingleObject(信号量);
创建();
CloseHandle(信号灯);/*您不需要它*/
}
void Graphics::create()
{
…可能引发各种异常的代码
}
void Graphics::create_callback()
{
释放信号量(信号量,1,空);
}

一个简单的解决方案是在抛出异常的线程中捕获异常(或者在调用函数之前检查参数以确定是否抛出异常),然后通过静态变量将异常传递给主线程,主线程可以在主线程中抛出异常


我会在WaitForSingleObject之后添加一个检查,以发现是否有异常正在等待抛出,如果有,则会抛出它。

我看到您从
回调调用
PostMessage
,然后使用循环和
睡眠
主动等待。将
PostMessage
替换为,这将等待消息处理完成。这样,处理器密集型循环就消失了。此外,您还可以使用
SendMessage
调用的返回代码(来自
HookProc
WM_CALLBACK
臂)传递错误信息。使用简单的数字代码(例如,非零表示错误)或传递异常对象(在这种情况下,您必须从异常处理程序在堆上进行分配,不能直接传递参数,因为它是堆栈分配的)

最后,使用synchronous
SendMessage
而不是async
PostMessage
意味着您不再需要从
HookProc
构建中间
callH
函数对象,因为您可以传递堆栈分配的
call
参数。这将导致更简单的代码

例如:

void Callback(HWND hwnd, boost::function<void(HWND,LPARAM)> call, LPARAM lParam)
{
    //send a message with a pointer to our function object in the WPARAM
    if (SendMessage(hwnd, WM_CALLBACK, &call, lParam))
    {
        // error handling.
    }
}
LRESULT CALLBACK HookProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    //check for our custom message
    if(msg == WM_CALLBACK)
    {
        //retreive the function pointer from the WPARAM
        boost::function<void(HWND,LPARAM)> *callH = (boost::function<void(HWND,LPARAM)>*)wParam;
        //call it, catching exceptions in the process.
        try 
        {
            (*callH)(hwnd,lParam);
            return 0;
        } 
        catch (...) 
        {
            return 1;
        }
    }
    else
        //if there was nothing relevant to us, call the old message procedure
        return CallWindowProc(hooked[hwnd], hwnd, msg, wParam, lParam);
}
//std::map<HWND, WNDPROC> hooked;
无效回调(HWND-HWND,boost::函数调用,LPARAM-LPARAM) { //在WPARAM中发送一条带有指向函数对象指针的消息 if(发送消息(hwnd、WM_回调和调用、LPRAM)) { //错误处理。 } } LRESULT回调HookProc(HWND HWND,UINT msg,WPARAM WPARAM,LPARAM LPARAM) { //检查我们的自定义消息 if(msg==WM\u回调) { //从WPARAM中检索函数指针 boost::function*callH=(boost::function*)wParam; //调用它,捕获过程中的异常。 尝试 { (*callH)(hwnd、lParam); 返回0; } 捕获(…) { 返回1; } } 其他的 //如果与我们无关,请调用旧的消息过程 返回CallWindowProc(钩住[hwnd]、hwnd、msg、wParam、lParam); } //标准::地图钩;
以及:

Graphics::Graphics(IWindow*\u窗口,大小2\u)
:丢失(false)、重置(false)、引用(0)、返回列(0xFF000000),
启动(错误)、退出(错误),
窗口(_窗口),大小(_大小)
{
窗口->添加参考();
HWND HWND=*((HWND*)窗口->获取句柄();
回调钩(hwnd);
回调(hwnd,boost::bind(&Graphics::create,this),0);
//无需等待,因为SendMessage是同步的。
}
void Graphics::create()
{
…可能会导致错误的代码
Graphics::Graphics(IWindow *_window, Size2<unsigned> _size)
:lost(false), reset(false), refCnt(0), backCol(0xFF000000),
started(false), exited(false),
window(_window), size(_size)
{
    window->AddRef();
    HWND hwnd = *((HWND*)window->GetHandle());
    CallbackHook(hwnd);
    Callback(hwnd, boost::bind(&Graphics::create, this), 0);

    // No need to wait, as SendMessage is synchronous.
}
void Graphics::create()
{
...code that may throw various exceptions
    started = true;
}
class Context
{
public:
    Context(HWND hwnd, const boost::function<void(HWND,LPARAM)>& f, LPARAM lParam)
    {
        // TODO: reroute call through Wrapper function.
    }

    void wait()
    {
        mutex::scoped_lock l(m);
        while (!finished)
        {
            c.wait(l);
        }
        if (ex)
            rethrow_exception(ex);
    }

private:
    void Wrapper()
    {
        try
        {
            f(/*params*/);
        }
        catch (...)
        {
            ex = current_exception();
        }
        mutex::scoped_lock l(m);
        finished = true;
        c.notify_all();
    }

    boost::function<void(HWND,LPARAM)> f;
    exception_ptr ex;
    bool finished;
    mutex m;
    condition c;
};

void Callback(HWND hwnd, const boost::function<void(HWND,LPARAM)>& f, LPARAM lParam)
{
    Context ctx(hwnd, f, lParam);

    ctx.wait();
}