Отмена операции LoadAsync по истечении периода ожидания и последующий вызов LoadAsync вызывает исключение.

Я работаю с SerialDevice на C ++ / winrt, и мне нужно прослушивать данные, поступающие через порт. Я могу успешно работать с SerialDevice, когда данные передаются через порт, но если ничего не читается, функция DataReader.LoadAsync () зависает, хотя я установил тайм-ауты с помощью SerialDevice.ReadTimeout () и SerialDevice.WriteTimeout (). Итак, чтобы отменить операцию, я использую операцию IAsyncOperation wait_for (), которая истекает через заданный интервал, и я вызываю IAsyncOperation's Cancel () и Close (). Проблема в том, что я больше не могу сделать еще один вызов DataReader.LoadAsync () без исключения take_ownership_from_abi. Как правильно отменить вызов DataReader.LoadAsync (), чтобы разрешить последующие вызовы LoadAsync () для того же объекта?

Чтобы обойти это, я попытался установить тайм-ауты SerialDevice, но это не повлияло на вызовы DataRead.LoadAsync (). Я также попытался использовать create_task с токеном отмены, который также не позволял дополнительный вызов LoadAsync (). Чтобы найти эту статью Кенни Керра, потребовалось много времени: https://kennykerr.ca/2019/06/10/cppwinrt-async-timeouts-made-easy/, где он описывает использование функции wait_for IAsyncOperation.

Вот инициализация 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 примерно до дня пробования других вещей и случайного поиска подсказок в разных сообщениях) - это я что-то упускаю или это действительно так? Спасибо!


person scalpel    schedule 18.07.2019    source источник
comment
после перехвата исключения при втором вызове LoadAsync я получил Идентификатор операции недействителен. Не уверен, к какому идентификатору относится исключение или что мне нужно исправить.   -  person scalpel    schedule 18.07.2019
comment
Итак, первая отмена действительно работает, но вы встречаете исключение take_ownership_from_abi для вызовов подпоследовательности? Не могли бы вы предоставить рабочий образец?   -  person Barry Wang    schedule 19.07.2019
comment
Конечно, у меня есть образец проекта консоли c ++ / winRT, демонстрирующий проблему. как бы вы хотели, чтобы я поделилась этим с вами? Тем временем я обнаружил, что если я поймаю и проигнорирую исключение, я могу повторно использовать объект DataReader и продолжить проверку, есть ли какие-либо данные в порту. Кажется, что это действительно так работает, но меня беспокоит выбрасываемое исключение и может ли оно привести к нестабильности приложения.   -  person scalpel    schedule 21.07.2019
comment
Что касается вашего рабочего образца, любой метод подойдет, если мы можем скачать и протестировать.   -  person Faywang - MSFT    schedule 22.07.2019
comment
Отображает ли ваша подробная информация об исключении результат: идентификатор операции недействителен.? У меня есть рабочий прием, который вы можете попробовать. Вы можете добавить Sleep (m_nTO) после вашего async.Close (); в функции LoadFromStream.   -  person Faywang - MSFT    schedule 25.07.2019
comment
Да. Я попробую и доложу.   -  person scalpel    schedule 27.07.2019
comment
Вот и все! Спасибо faywang!   -  person scalpel    schedule 29.07.2019


Ответы (1)


Причина. По истечении времени ожидания асинхронный объект находится в 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;
}
person Faywang - MSFT    schedule 30.07.2019