Хорошо, один для ТАК коллективного разума ...
У меня есть код, который до сегодняшнего дня отлично работал во многих системах и развернут на многих сайтах. Он включает потоки, считывающие и записывающие данные из последовательного порта.
При попытке проверить новое устройство мой код был завален 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, к сведению), но это похоже на отговорку.
Ну и Vista SP1 Business 32-bit, за мои грехи.
Прежде чем я просто отнесу это к «чужой проблеме», есть ли у кого-нибудь идеи о том, что может вызвать это?





Как вы настраиваете структуру OVERLAPPED перед ReadFile? - Я всегда обнуляю их (кроме hEvent, очевидно), что, возможно, отчасти является суеверием, но у меня такое чувство, что это вызывало у меня проблемы в прошлом.
Боюсь, винить драйвер (если он не MS, а не просто небольшая настройка из справочника) не совсем нереально. Написать драйвер COM - невероятно сложная вещь, и сложность его тестирования состоит в том, что каждое когда-либо написанное приложение использует последовательные порты и их IOCTL несколько по-разному.
Другая распространенная проблема - не настроить весь порт - например, не вызывать SetCommTimeouts или SetupComm. Понятия не имею, совершаете ли вы такого рода ошибку, но я встречал людей, которые говорили, что не используют тайм-ауты, когда на самом деле имели в виду, что они не вызывали SetCommTimeouts, поэтому они используют их, но у них нет понятие, на что они настроены ...
Такие вещи могут быть убийственными для сторонних драйверов COM, потому что людям часто сошло с рук всякая старая ерунда с драйвером MS, и он не всегда работает одинаково с другим устройством.
Я согласен с тем, что тайм-ауты выглядят вероятной причиной, особенно потому, что ввод не теряется, а вызов ReadFile читает только один байт за раз. Однако, если приложение правильно настраивает порт, вполне реально винить драйвер, в том числе драйвер MS.
Я очищаю структуру OVERLAPPED (кроме hEvent) и вызываю SetCommTimeouts с нулями во всех полях в COMMTIMEOUTS. Я попытался перейти на ввод / вывод без перекрытия и получил тот же результат. Пора попробовать другой порт связи ...
помимо обнуления OVERLAPPED, вы также можете проверить, как вы устанавливаете olap.hEvent, то есть каковы ваши аргументы CreateEvent? Если вы создаете событие с предварительным сигналом (т.е. третий аргумент CreateEvent - ИСТИНА), я бы ожидал немедленного возврата. Кроме того, не забывайте, что если вы укажете manualReset (второй аргумент CreateEvent) как FALSE, GetOverlappedResult () поможет вам очистить событие, что может объяснить, почему он работает во второй раз.
Не могу сказать из вашего фрагмента, влияет ли это на вас - надеюсь, это поможет.
Я не верю, что это ваша проблема, но вы неправильно используете
WaitForSingleObjectEx. Вы должны искать (1)dwWait == WAIT_OBJECT_0или (2)dwWait == WAIT_TIMEOUT && dwError == ERROR_IO_PENDING.