2015-04-20 66 views
0

我有一個函數調用Concurrency :: create_task在後臺執行一些工作。在該任務中,需要在類StreamSocket上調用connectAsync方法,以便將套接字連接到設備。一旦設備連接,我需要獲取連接套接字內的一些引用(如輸入和輸出流)。。在C++/cx中的任務.wait()拋出異常

由於它是一種異步方法,將返回一個IAsyncAction,我需要在connectAsync函數上創建另一個任務,我可以等待。這工作沒有等待,但是當我嘗試wait()在這個內在的任務爲了錯誤檢查而出現複雜化。

Concurrency::create_task(Windows::Devices::Bluetooth::Rfcomm::RfcommDeviceService::FromIdAsync(device_->Id)) 
    .then([ this ](Windows::Devices::Bluetooth::Rfcomm::RfcommDeviceService ^device_service_) 
{ 
    _device_service = device_service_; 
    _stream_socket = ref new Windows::Networking::Sockets::StreamSocket(); 

    // Connect the socket 
    auto inner_task = Concurrency::create_task(_stream_socket->ConnectAsync(
     _device_service->ConnectionHostName, 
     _device_service->ConnectionServiceName, 
     Windows::Networking::Sockets::SocketProtectionLevel::BluetoothEncryptionAllowNullAuthentication)) 

     .then([ this ]() 
    { 

     //grab references to streams, other things. 

    }).wait(); //throws exception here, but task executes 

基本上,我已經想通了,創建初始任務連接在同一個線程(大概是UI),還執行任務和內部任務。每當我嘗試從外部任務調用.wait()的內部任務時,我立即得到一個異常。但是,內部任務將完成併成功連接到設備。

爲什麼我的異步鏈在UI線程上執行?我如何正確地等待這些任務?

+0

您是否嘗試過記錄異常?它可能會回答爲什麼它被拋出。 – Siguza

+0

我有,它實際上不是一個例外,是拋出。我似乎無法捕捉到任何缺少全面捕捉(...)的東西。我試過了platform :: exception,並且關於我能想到的每種數據類型。 – turkycat

+0

也嘗試過'void *'和'nullptr_t'嗎? – Siguza

回答

3

一般而言,您應該避免.wait()並繼續異步鏈。如果由於某種原因需要阻塞,唯一的防呆機制是從後臺線程(例如WinRT線程池)顯式運行代碼。

可以嘗試使用.then()重載需要task_options並通過concurrency::task_options(concurrency::task_continuation_context::use_arbitrary()),但不保證延續將在另一個線程上運行;它只是說,如果確實如此,請參閱documentation here

1

您可以設置一個事件並讓主線程等待它。我已經完成了一些IO異步操作。下面是使用線程池,利用事件來等待工作的一個基本的例子:

TEST_METHOD(ThreadpoolEventTestCppCx) 
    { 

     Microsoft::WRL::Wrappers::Event m_logFileCreatedEvent; 
     m_logFileCreatedEvent.Attach(CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, WRITE_OWNER | EVENT_ALL_ACCESS)); 

     long x = 10000000; 

     auto workItem = ref new WorkItemHandler(
      [&m_logFileCreatedEvent, &x](Windows::Foundation::IAsyncAction^ workItem) 
     {    

      while (x--); 

      SetEvent(m_logFileCreatedEvent.Get()); 

     }); 

     auto asyncAction = ThreadPool::RunAsync(workItem); 

     WaitForSingleObjectEx(m_logFileCreatedEvent.Get(), INFINITE, FALSE); 


     long i = x; 
    } 

這裏是除了它有類似的例子還包括一個位Windows運行時異步IO的:

TEST_METHOD(AsyncOnThreadPoolUsingEvent) 
{ 

    std::shared_ptr<Concurrency::event> _completed = std::make_shared<Concurrency::event>(); 


    int i; 

    auto workItem = ref new WorkItemHandler(
     [_completed, &i](Windows::Foundation::IAsyncAction^ workItem) 
    { 

     Windows::Storage::StorageFolder^ _picturesLibrary = Windows::Storage::KnownFolders::PicturesLibrary; 

     Concurrency::task<Windows::Storage::StorageFile^> _getFileObjectTask(_picturesLibrary->GetFileAsync(L"art.bmp")); 

     auto _task2 = _getFileObjectTask.then([_completed, &i](Windows::Storage::StorageFile^ file) 
     { 
      i = 90210; 

      _completed->set(); 

     }); 

    }); 

    auto asyncAction = ThreadPool::RunAsync(workItem); 

    _completed->wait(); 


    int j = i; 

} 

我嘗試使用一個事件來等待Windows運行時異步工作,但它被阻止。這就是爲什麼我必須使用線程池。