【问题标题】:.wait() on a task in c++/cx throws exception.wait() 在 c++/cx 中的任务上抛出异常
【发布时间】:2015-06-27 08:22:35
【问题描述】:

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

【问题讨论】:

  • 您是否尝试过记录异常?它可能包含为什么抛出它的答案。
  • 我有,其实不是抛出异常。我似乎无法用任何不全面的catch(...) 来捕捉它。我已经尝试过 platform::exception 以及我能想到的所有数据类型。
  • 也试过void*nullptr_t
  • 我现在有,仍然没有骰子。一切总是在同一个线程上运行,我很确定这是由于 UI 线程上的 .wait() 造成的,因为我过去曾在 UI 线程上直接尝试过 .wait() (偶然)一次或两次并看到了同样的行为。
  • 你会用C++11吗?如果是这样,您可以使用std::current_exception() 获取std::exception_ptr,通过将指向它的指针转换为void*,然后转换为unsigned int**unsigned long long**(32 位或64 位),您可以从中获取至少一些信息),取消引用两次(或 3 次,如果它看起来是一个有效的指针),然后将结果写入std::cout。据说会导致未定义的行为,但指针需要存储在某个地方,对吗?我会说至少值得一试。

标签: multithreading asynchronous c++-cx


【解决方案1】:

一般而言,您应该避免使用.wait() 并继续异步链。如果您出于某种原因需要阻止,唯一的万无一失的机制是从后台线程(例如,WinRT 线程池)显式运行您的代码。

可以尝试使用.then() 重载,该重载采用task_options 并传递concurrency::task_options(concurrency::task_continuation_context::use_arbitrary()),但不保证继续将在另一个上运行线;它只是说如果这样做就可以了——见documentation here

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2011-11-12
      • 1970-01-01
      • 1970-01-01
      • 2023-03-14
      • 1970-01-01
      • 1970-01-01
      • 2012-11-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多