Перекрывающийся файл чтения Win32 на COM-порте, возвращающий ERROR_OPERATION_ABORTED

Хорошо, один для коллективного разума SO...

У меня есть код, который до сегодняшнего дня прекрасно работал на многих системах и развернут на многих сайтах. Он включает в себя потоки, читающие и записывающие данные из последовательного порта.

При попытке проверить новое устройство мой код был завален ошибками 995 ERROR_OPERATION_ABORTED, вызывающими GetOverlappedResult после ReadFile. Иногда чтение работало, иногда я получал эту ошибку. Простое игнорирование ошибки и повторная попытка, как ни удивительно, сработали бы без потери каких-либо данных. ClearCommError не требуется.

Вот фрагмент.

if (!ReadFile(handle,&c,1,&read, &olap))
    {
        if (GetLastError() != ERROR_IO_PENDING)
        {
            logger().log_api(LOG_ERROR,"ser_rx_char:ReadFile");
            throw Exception("ser_rx_char:ReadFile");
        }
    }

    WaitForSingleObjectEx(r_event, INFINITE, true);  // alertable, so, thread can be closed correctly.

    if (GetOverlappedResult(handle,&olap,&read, TRUE) != 0)
    {
        if (read != 1)
            throw Exception("ser_rx_char: no data");

        logger().log(LOG_VERBOSE,"read char %d ( read = %d) ",c, read);
    }
    else
    {
        DWORD err = GetLastError();
        if (err != 995)   //Filters our ERROR_OPERATION_ABORTED
        {
            logger().log_api(LOG_ERROR,"ser_rx_char: GetOverlappedResult");
            throw Exception("ser_rx_char:GetOverlappedResult");
        }
    }

Мое первое предположение заключается в том, что виноват драйвер COM-порта, который я раньше не использовал (это порт RS422 на Blackmagic Decklink, FYI), но это похоже на отговорку.

О, и Vista SP1 Business 32-bit, за мои грехи.

Прежде чем я просто отнесу это к «Чей-то другой проблеме», есть ли у кого-нибудь идеи о том, что может вызвать это?


person Roddy    schedule 20.11.2008    source источник
comment
Я не думаю, что это ваша проблема, но вы неправильно используете WaitForSingleObjectEx. Вы должны проверить (1) dwWait == WAIT_OBJECT_0 или (2) dwWait == WAIT_TIMEOUT && dwError == ERROR_IO_PENDING.   -  person jww    schedule 20.09.2012


Ответы (2)


Как вы устанавливаете структуру OVERLAPPED перед ReadFile? - Я всегда обнуляю их (разумеется, кроме hEvent), что, возможно, отчасти является суеверием, но у меня есть ощущение, что это доставляло мне проблемы в прошлом.

Боюсь, обвинять драйвер (если он не MS, а не просто малюсенький твик из референса) не совсем нереально. Написание COM-драйвера — невероятно сложная задача, и сложность его тестирования заключается в том, что каждое когда-либо написанное приложение использует последовательные порты и их IOCTL немного по-разному.

Другая распространенная проблема заключается в том, чтобы не настроить весь порт, например, не вызывая SetCommTimeouts или SetupComm. Я понятия не имею, делаете ли вы такую ​​ошибку, но я встречал людей, которые говорят, что они не используют тайм-ауты, хотя на самом деле они имеют в виду, что они не вызывали SetCommTimeouts, поэтому они используют их, но не имеют представление о том, на что они настроены...

Подобные вещи могут быть убийственными для сторонних COM-драйверов, потому что людям часто сходит с рук любая старая хрень с драйвером MS, и она не всегда работает одинаково с другим устройством.

person Will Dean    schedule 20.11.2008
comment
Я согласен с тем, что тайм-ауты выглядят вероятной причиной, тем более что никакие входные данные не теряются, а вызов ReadFile считывает только один байт за раз. Однако, если приложение правильно настраивает порт, вполне реально обвинить драйвер, в том числе, если это драйвер MS. - person Windows programmer; 21.11.2008
comment
Я очищаю структуру OVERLAPPED (кроме hEvent) и вызываю SetCommTimeouts с нулями во всех полях в COMMTIMEOUTS. Я попытался перейти на неперекрывающийся ввод-вывод и получил тот же результат. Время попробовать другой коммуникационный порт... - person Roddy; 21.11.2008

в дополнение к обнулению OVERLAPPED вы также можете проверить, как вы устанавливаете olap.hEvent, то есть какие у вас аргументы для CreateEvent? Если вы создаете событие, которое предварительно сигнализируется (т. Е. Третий аргумент CreateEvent равен TRUE), я ожидаю немедленного возврата. Кроме того, не забывайте, что если вы укажете manualReset (второй аргумент CreateEvent) как FALSE, GetOverlappedResult() поможет вам очистить событие, что может объяснить, почему он работает во второй раз.

Не могу сказать по вашему фрагменту, влияет ли на вас что-либо из этого - надеюсь, это поможет.

person Community    schedule 06.05.2009