CloseHandle() возвращает до того, как последовательный порт будет фактически закрыт

Я дергаю себя за волосы, пытаясь понять, когда завершается закрытие последовательного порта, чтобы я мог открыть его снова. Оказывается, что CloseHandle() возвращается до того, как порт фактически разблокирован.

Я открываю последовательный порт используя CreateFile(FILE_FLAG_OVERLAPPED), связав его с CompletionPort используя CreateIoCompletionPort(), чтение / запись с помощью ReadFile(), WriteFile() и закрывая его, используя CloseHandle(),

Я заметил, что если я закрою и снова открою последовательный порт достаточно быстро, я получу ERROR_ACCESS_DENIED обратно из CreateFile(), Это происходит несмотря на то, что я жду CloseHandle() для возврата, затем ожидая возврата всех ожидающих операций чтения / записи, связанных с этим дескриптором, из порта завершения. Конечно, есть лучший способ:)

Как закрыть последовательный порт синхронно? Пожалуйста, не повторяйте петли, сон () или другие дешевые хаки.

РЕДАКТИРОВАТЬ: Может быть, это связано с моим использованием портов завершения и FILE_FLAG_OVERLAPPED. Я получаю обратный вызов, когда операции чтения / записи завершены. Есть ли какой-то обратный вызов для закрытия порта?

3 ответа

Решение

Я считаю, что проблема с драйвером, который обслуживает COM-порт. Следовательно - не будет никакого API, чтобы "фактически закрыть" COM-порт.

Кстати, после закрытия дескриптора файла не нужно ждать завершения всех выдающихся операций ввода-вывода с ошибками. В это время CloseHandle возвращает все невыполненные операции ввода / вывода уже завершены / отменены, вы просто получаете обратные вызовы асинхронно (будь то через порт завершения или очередь APC, неважно).

В частности, драйверы FTDI (те, которые эмулируют COM->USB), как известно, очень сложны.

Я могу только рекомендовать попробовать очистить данные перед закрытием ручки. Вы можете дождаться завершения всех операций ввода-вывода, прежде чем закрывать COM-порт (если это применимо для вашего случая). Или вы можете позвонить SetCommMask а также WaitCommEvent чтобы не было ожидающих отправки данных. Надеюсь, это может помочь.

РЕДАКТИРОВАТЬ:

Есть ли CloseHandle немедленно (до его возвращения) отменить все ожидающие операции ввода-вывода для дескриптора файла?

Строго говоря - нет.

Могут быть другие ссылки, оставленные на объект файла. Например, код режима пользователя может вызвать DuplicateHandleили драйвер режима ядра может вызвать ObReferenceObjectByXXXX, В таком случае объект, на который ссылается дескриптор, не обязательно освобождается.

Когда последняя ручка закрыта DispatchCleanup называется. В соответствии с этим он должен отменить все выдающиеся операции ввода-вывода.

Однако, хотя один поток находится в пределах CloseHandle - теоретически вы можете выполнить другой ввод / вывод из другого потока (если вам повезет - дескриптор все равно будет действителен). Пока вы находитесь в вызове функции ввода / вывода (например, WriteFile или т. д.) ОС временно увеличивает счетчик ссылок на объект. Это, в свою очередь, может запустить другой ввод / вывод, который не будет отменен напрямую CloseHandle призывание.

Однако в этом случае дескриптор будет закрыт O / S сразу же после выдачи нового I/O, поскольку счетчик ссылок на объект снова достиг 0.

Так что в таком извращенном сценарии может возникнуть ситуация, когда сразу после звонка CloseHandle Вы не можете снова открыть файл.

Убедитесь, что ваше устройство чтения и записи завершилось неудачно (с неверным дескриптором) после того, как вы выполнили запрос CloseHandle() (предположительно в каком-то другом потоке), прежде чем пытаться снова коснуться устройства. Вы можете использовать это как подсказку, чтобы очистить всю вашу обработку ввода-вывода перед попыткой выпустить другой CreateFile. Я должен сказать, что порты завершения кажутся излишне барочными.

Когда вы открываете COM-порт в потоке, операционная система открывает другой скрытый поток для выполнения операций ввода-вывода. Я также пытаюсь решить проблему закрытия порта. Насколько я могу сказать, один метод, который может работать: 1) приостановить поток, который открыл COM-порт, 2) PurgeComm(), чтобы остановить все операции ввода-вывода и очистить все буферы ввода / вывода для чтения / записи, и 3) затем попытаться закрыть COM-порт. Может быть задействован объект waitforsingle, чтобы определить, когда поток с COM-портом фактически приостанавливается. Если COM-порт не нужно обязательно закрывать, я рассматриваю возможность оставить COM-порт открытым и позволить WinProc обработать команду IDM_Exit для закрытия COM-порта, потоков и приложения. Не то, что я хотел, а вариант, с которым я мог бы жить. Я использую соединение USB с последовательным портом и не уверен, какие проблемы это вызывает у меня. Я знаю, что если вы используете интерфейс USB к последовательному порту, вам нужно установить высокий уровень контакта 20 (DTR). Контакт 20 помогает питать интерфейс, но обеспечивает только около 30 мА или около того. Если все это работает, я сделаю обновление к этому посту и сообщу, как, если я смог закрыть COM-порт. Windows запуталась в драйвере последовательного порта и, кажется, довольна, чтобы оставить вещи в беспорядке!

Другие вопросы по тегам