对c++/cx中的任务执行.wait()会引发异常



我有一个函数,它调用Concurrent::create_task在后台执行一些工作。在该任务中,需要调用StreamSocket类上的connectAsync方法,以便将套接字连接到设备。一旦连接了设备,我就需要获取一些对连接的套接字内部事物的引用(比如输入和输出流)。

由于这是一个异步方法,将返回一个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线程上执行?我如何才能正确地等待这些任务?

通常,您应该避免.wait(),而只是继续异步链。如果出于某种原因需要阻止,唯一的防傻机制就是从后台线程(例如,WinRT线程池)显式运行代码。

可以尝试使用.then()重载,该重载接受task_options并传递concurrency::task_options(concurrency::task_continuation_context::use_arbitrary()),但不能保证继续将在另一个线程上运行;它只是说,如果它这样做就可以了——请参阅这里的文档。

您可以设置一个事件并让主线程等待它。我已经用一些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运行时异步工作,但它被阻止了。这就是为什么我必须使用线程池。

最新更新