异常处理,WinRT C ++并发异步任务 [英] Exception handling, WinRT C++ concurrency async tasks

查看:280
本文介绍了异常处理,WinRT C ++并发异步任务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须在C ++中实现一个异步HTTP GET,我们必须能够将应用程序提交到Windows 8商店。



我的问题如下:



我找到了一个合适的示例代码,它实现了一个HttpRequest类 http://code.msdn.microsoft.com/windowsapps/HttpClient-sample-55700664



此示例工作如果URI是正确的,但如果URI指向无效/不存在的地方(例如:www.google22.com),则会抛出异常。这将是罚款,如果我可以捕获异常,但我不能弄清楚如何或在哪里应该捕获它。



现在一些代码。
这是调用async,concurrency ::任务的方法抛出异常:

  try {
...
Web :: HttpRequest httpRequest;
httpRequest.GetAsync(uri,cancellationTokenSource.get_token())
.then([](concurrency :: task< std :: wstring> response)
{
try {
response.get();
}
catch(...){
int i = 1;
}
返回响应;
})
...
} catch(...){
...
}

这是GetAsync方法的相关段(方法的结尾):

  //返回在HTTP操作完成时完成的任务。 
//我们将回调传递给延续,因为
//回调的生命周期必须超过操作,以确保取消
//正常工作。
return completionTask.then([this,stringCallback](tuple< HRESULT,wstring> resultTuple)
{
//如果GET操作失败,抛出一个异常
CheckHResult std :: get< 0>(resultTuple));

statusCode = stringCallback-> GetStatusCode();
reasonPhrase = stringCallback-> GetReasonPhrase();

return std :: get< 1>(resultTuple);
});

CheckHResult行抛出异常,代码如下:

  inline void CheckHResult(HRESULT hResult)
{
if(hResult == E_ABORT)
{
concurrency :: cancel_current_task );
}
else if(FAILED(hResult))
{
throw Platform :: Exception :: CreateException(hResult);
}
}



我有一个try-catch GetAsync调用和我还在.then继续lambda中有一个try-catch。



在相关的Microsoft文档( http://msdn.microsoft.com/en-us/library/windows/apps/hh780559.aspx )it states任务抛出的异常应该可以在链中的下一个任务中捕获,但不知何故,它在我的情况下不工作。此外,即使整个调用的try-catch捕获异常,它只是滑过一切...



任何人有这个问题吗?我认为我已经尝试了官方文档中说明的一切,但它仍然允许异常去疯狂和崩溃的应用程序。我错过了什么?



编辑:



除了异常处理之外什么也不做,它仍然不捕获由.GetAsync中的任务抛出的异常



清理代码:

  try 
{
Windows :: Foundation :: Uri ^ uri;
uri = ref new Windows :: Foundation :: Uri(uri_string_to_fetch);

concurrency :: cancellation_token_source cancellationTokenSource = concurrency :: cancellation_token_source();

Web :: HttpRequest httpRequest;
OutputDebugString(L开始获取uri ... \\\
);
httpRequest.GetAsync(uri,cancellationTokenSource.get_token())
.then([](concurrency :: task< std :: wstring> response)
{
try {
response.get();
}
catch(...){
OutputDebugString(Lunknown Exception);
}
})
.then([](concurrency :: task< void> t)
{
try {
t.get();
// .get 't throw,所以我们成功了。
}
catch(Platform :: Exception ^ e){
// handle error
OutputDebugString(LPlatform :: Exception);
}
catch(...){
OutputDebugString(Lunknown Exception);
}
});
}
catch(Platform :: Exception ^ ex){
OutputDebugString(LPlatform :: Exception);
errorCallback(-1);
}
catch(...){
OutputDebugString(Lunknown Exception);
errorCallback(-2);
}

这仍然会导致异常消息崩溃:机会异常在0x75644B32在App1.exe:Microsoft C ++异常:Platform :: COMException ^在内存位置0x077EEC28。 HRESULT:0x800C0005



此外,当我在代码中放置一些断点时,它会显示异常在第一个.then被调用之前滑过。我在这些位置(在简化/清理代码中)设置断点:




  • 在GetAsync调用之前

  • 插入到GetAsync,到 CheckHResult(std :: get< 0>(resultTuple)); 行,将抛出异常

  • try&catch case / block



执行顺序,使用断点测试:



<在GetAsync调用[OK]
  • 之前,在$ GetAsync中调用

  • 现在应用崩溃了,每次尝试try ,继续

  • 现在第一个 .then

  • 另一个应用程式层级例外未被任何catch块捕获

  • 现在是第一个<

  • 第二个
  • / em>的catch甚至不会捕获任何异常

    和打印的调试日志,顺序:
    - 开始获取uri ...
    - 在App1.exe中的0x75644B32的第一次例外:Microsoft C ++异常:Platform :: COMException ^在内存位置0x082FEEF0。 HRESULT:0x800C0005
    - 在App1.exe中0x75644B32的第一次例外:Microsoft C ++异常:[rethrow]在内存位置0x00000000。
    - 在App1.exe中0x75644B32的第一次例外:Microsoft C ++异常:Platform :: COMException ^在内存位置0x082FE670。 HRESULT:0x800C0005
    - 在App1.exe的0x75644B32的第一次例外:Microsoft C ++异常:Platform :: COMException ^在内存位置0x082FDD88。 HRESULT:0x800C0005
    - 未知异常



    发生了什么?

    解决方案

    在并发运行时,在任务执行期间发生的任何未处理的异常将被推迟以供以后观察。这样,你可以在链接末尾添加一个基于任务的延续,并处理错误。



    这样的东西:

      httpRequest.GetAsync(uri,cancellationTokenSource.get_token())
    .then([](concurrency :: task< std :: wstring> response)
    {
    try {
    response.get();
    }
    catch(...){
    int i = 1;
    }
    return response;
    })
    .then([](concurrency :: task< void> t)
    {
    try {
    t.get ();
    // .get()没有抛出,所以我们成功了
    }
    catch(Platform :: Exception :: CreateException ^ e){
    // handle error
    }
    });

    调用 .get 会触发任何异常在任务链(如果有)中提出。
    有关详细信息,请参阅并发运行时中的异常处理


    I have to implement an async HTTP GET in C++ and we have to be able to submit the app to the Windows 8 Store.

    My problem is the following:

    I've found a suitable Sample code which implements an HttpRequest class http://code.msdn.microsoft.com/windowsapps/HttpClient-sample-55700664

    This example works if the URI is correct but throws an exception if the URI points to an invalid / non existing place (like: www.google22.com). This would be fine if I could catch the exception but I cannot figure it out how or where should I catch it.

    Now some code. This is the call to the async, concurrency::task based method which throws the exception:

    try {
    ...
    Web::HttpRequest httpRequest;
        httpRequest.GetAsync(uri, cancellationTokenSource.get_token())
            .then( []  (concurrency::task<std::wstring> response)
        {
            try {
                response.get();
            }
            catch( ... ) {
                int i = 1;
            }
            return response;
        })
    ...
    } catch ( ... ) {
    ...
    }
    

    And this is the relevant segment of the GetAsync method (the end of the method):

    // Return a task that completes when the HTTP operation completes. 
    // We pass the callback to the continuation because the lifetime of the 
    // callback must exceed the operation to ensure that cancellation 
    // works correctly.
    return completionTask.then([this, stringCallback](tuple<HRESULT, wstring> resultTuple)
    {
        // If the GET operation failed, throw an Exception.
        CheckHResult(std::get<0>(resultTuple));
    
        statusCode = stringCallback->GetStatusCode();
        reasonPhrase = stringCallback->GetReasonPhrase();
    
        return std::get<1>(resultTuple);
    });
    

    The CheckHResult line throws the exception, it's code:

    inline void CheckHResult(HRESULT hResult)
    {
    if (hResult == E_ABORT)
    {
        concurrency::cancel_current_task();
    }
    else if (FAILED(hResult))
    {
        throw Platform::Exception::CreateException(hResult);
    }
    }
    

    I have a try-catch around the GetAsync call and I also have a try-catch in the .then continuation lambda.

    In the relevant Microsoft documentation ( http://msdn.microsoft.com/en-us/library/windows/apps/hh780559.aspx ) it states that exceptions thrown by a task should be catchable in the next task in the chain but somehow it doesn't work in my case. Additionally not even the try-catch around the whole call catches the exception, it just slips through everything...

    Anyone had this problem? I think I've tried everything stated in the official documentations but it still lets the exception go berserk and crash the app. What do I miss?

    EDIT:

    I've modified the code to do nothing else but exception handling and it still doesn't catch the exception thrown by the task in .GetAsync

    Cleaned-up code:

    try
    {
      Windows::Foundation::Uri^ uri;
      uri = ref new Windows::Foundation::Uri( uri_string_to_fetch );
    
      concurrency::cancellation_token_source cancellationTokenSource = concurrency::cancellation_token_source();
    
      Web::HttpRequest httpRequest;
      OutputDebugString( L"Start to fetch the uri...\n" );
      httpRequest.GetAsync(uri, cancellationTokenSource.get_token())
        .then([](concurrency::task<std::wstring> response)
      {
        try {
          response.get();
        }
        catch( ... ) {
          OutputDebugString(L"unknown Exception");
        }
      })
      .then([](concurrency::task<void> t)
      {
        try {
          t.get();
          // .get() didn't throw, so we succeeded.
        }
        catch (Platform::Exception^ e) {
          // handle error
          OutputDebugString(L"Platform::Exception");
        }
        catch (...) {
          OutputDebugString(L"unknown Exception");
        }
      });
    } 
    catch (Platform::Exception^ ex) {
      OutputDebugString(L"Platform::Exception");
      errorCallback(-1);
    } 
    catch ( ... ) {
      OutputDebugString(L"unknown Exception");
      errorCallback(-2);
    }
    

    This still gives me a crash with the exception message: First-chance exception at 0x75644B32 in App1.exe: Microsoft C++ exception: Platform::COMException ^ at memory location 0x077EEC28. HRESULT:0x800C0005

    Additionally when I put some breakpoints in the code it shows that the exception slips through everything before the first .then would be called. I've put breakpoints in these locations (in the simplified / cleaned up code):

    • before the GetAsync call
    • into the GetAsync, to the CheckHResult(std::get<0>(resultTuple)); line which throws the exception
    • into every try and catch case / block

    Order of execution, tested with breakpoints:

    1. before the GetAsync call [OK]
    2. in the GetAsync, the line which will throw the exception [OK]
    3. now the app crashes, slips through every try-catch, continue
    4. now the line in the first .then gets called, in it's try block
    5. another app level exceptions not catched by any catch block
    6. now the first .then's catch block
    7. second .then method's try block
    8. and nothing more, the second .then's catch doesn't even catch any exception

    And the printed debug logs, in order: - Start to fetch the uri... - First-chance exception at 0x75644B32 in App1.exe: Microsoft C++ exception: Platform::COMException ^ at memory location 0x082FEEF0. HRESULT:0x800C0005 - First-chance exception at 0x75644B32 in App1.exe: Microsoft C++ exception: [rethrow] at memory location 0x00000000. - First-chance exception at 0x75644B32 in App1.exe: Microsoft C++ exception: Platform::COMException ^ at memory location 0x082FE670. HRESULT:0x800C0005 - First-chance exception at 0x75644B32 in App1.exe: Microsoft C++ exception: Platform::COMException ^ at memory location 0x082FDD88. HRESULT:0x800C0005 - unknown Exception

    What is happening??

    解决方案

    In the Concurrency Runtime any unhandled exception that occurs during the execution of a task is deferred for later observation. In this way, you could add a task based continuation at the end of the chain and handle errors there.

    Something like this:

    httpRequest.GetAsync(uri, cancellationTokenSource.get_token())
    .then([](concurrency::task<std::wstring> response)
    {
        try {
            response.get();
        }
        catch( ... ) {
            int i = 1;
        }
        return response;
    })
    .then([](concurrency::task<void> t)
    {
        try {
            t.get();
            // .get() didn't throw, so we succeeded.
        }
        catch (Platform::Exception::CreateException^ e) {
            // handle error
        }
    });
    

    The call to .get triggers any exceptions that were raised in the task chain (if any). For more details you can read Exception Handling in the Concurrency Runtime.

    这篇关于异常处理,WinRT C ++并发异步任务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆