我有一个调用Concurrency :: create_task的函数在后台执行一些工作。在该任务中,需要在connectAsync
类上调用StreamSocket
方法以将套接字连接到设备。连接设备后,我需要获取连接套接字内部的一些引用(如输入和输出流)。
由于它是一个异步方法并且将返回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 :(得分:3)
通常,您应该避免.wait()
并继续异步链。如果由于某种原因需要阻塞,唯一可靠的机制是从后台线程(例如,WinRT线程池)显式运行代码。
你可以尝试使用.then()
重载task_options
并传递concurrency::task_options(concurrency::task_continuation_context::use_arbitrary())
,但不保证> strong>延续将在另一个线程上运行;它只是说如果它这样做就行了 - 见documentation here。
答案 1 :(得分: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运行时异步工作,但它已被阻止。这就是我必须使用线程池的原因。