.wait()对c ++ / cx中的任务抛出异常

时间:2015-04-20 14:33:31

标签: multithreading asynchronous c++-cx

我有一个调用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线程上执行?我怎样才能正确地等待这些任务?

2 个答案:

答案 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运行时异步工作,但它已被阻止。这就是我必须使用线程池的原因。