超时后取消LoadAsync操作,然后再调用LoadAsync会引发异常

时间:2019-07-18 08:28:27

标签: asynchronous async-await c++-winrt

我正在使用C ++ / winrt上的SerialDevice,需要侦听来自端口的数据。当数据通过端口流传输时,即使我通过SerialDevice.ReadTimeout()和SerialDevice.WriteTimeout()设置了超时,如果没有读取任何内容,我也可以成功地与SerialDevice一起使用,但DataReader.LoadAsync()函数会挂起。因此,要取消操作,我使用的是IAsyncOperation的wait_for()操作,该操作在提供的时间间隔后超时,我调用IAsyncOperation的Cancel()和Close()。问题是,如果没有获取take_ownership_from_abi异常,我将无法再调用DataReader.LoadAsync()。如何正确取消DataReader.LoadAsync()调用以允许后续对同一对象的LoadAsync()调用?

要解决此问题,我尝试设置SerialDevice的超时,但是它不影响DataRead.LoadAsync()调用。我还尝试过使用带有取消令牌的create_task,该令牌也不允许对LoadAsync()的附加调用。经过大量搜索,找到肯尼·克尔的这篇文章: https://kennykerr.ca/2019/06/10/cppwinrt-async-timeouts-made-easy/ 他在其中描述了IAsyncOperation的wait_for函数的用法。

这是SerialDevice和DataReader的初始化:

        DeviceInformation deviceInfo = devices.GetAt(0);
        m_serialDevice = SerialDevice::FromIdAsync(deviceInfo.Id()).get();
        m_serialDevice.BaudRate(nBaudRate);
        m_serialDevice.DataBits(8);
        m_serialDevice.StopBits(SerialStopBitCount::One);
        m_serialDevice.Parity(SerialParity::None);
        m_serialDevice.ReadTimeout(m_ts);
        m_serialDevice.WriteTimeout(m_ts);

        m_dataWriter = DataWriter(m_serialDevice.OutputStream());
        m_dataReader = DataReader(m_serialDevice.InputStream());

这是LoadAsync调用:

    AsyncStatus iainfo;

        auto async = m_dataReader.LoadAsync(STREAM_SIZE);
    try {
        auto iainfo = async.wait_for(m_ts);
    }
    catch (...) {};

    if (iainfo != AsyncStatus::Completed)
    {
        async.Cancel();
        async.Close();
        return 0;
    }
    else
    {
        nBytesRead = async.get();
        async.Close();
    }

因此,在AsyncStatus未完成的情况下,将调用IAsyncOperation Cancel()和Close(),根据文档,它们应取消Async调用,但是现在在后续的LoadAsync调用中,我将获得take_ownership_from_abi异常。 有人知道我在做什么错吗?为什么最初不支持SerialDevice超时?有没有更好的方法来取消Async调用,而无需再次初始化DataReader来允许进一步的调用?通常,感觉C ++ / winrt空间中的活动很少,并且文档严重缺乏(甚至在大约一天尝试其他东西并通过不同的帖子随机搜索线索之前,都没有找到wait_for方法)-是有什么我想念的,或者真的是这样吗? 谢谢!

1 个答案:

答案 0 :(得分:0)

原因::等待时间结束后,异步对象位于AsyncStatus::Started state中。这意味着异步对象仍在运行。

解决方案::当您使用 close()方法时,可以使用 Sleep(m_nTO)让异步操作有足够的时间关闭。请参考以下代码。

if (iainfo != AsyncStatus::Completed)
{
    m_nReadCount++;
    //Sleep(m_nTO);
    async.Cancel();
    async.Close();
    Sleep(m_nTO);

    return 0;
}