我正在使用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方法)-是有什么我想念的,或者真的是这样吗? 谢谢!
答案 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;
}