CloseHandle()在串口实际关闭之前返回

时间:2012-01-16 20:16:21

标签: windows winapi serial-port iocp io-completion-ports

我拉着我的头发试图弄清楚串口什么时候关闭所以我可以重新打开它。事实证明,CloseHandle()在端口实际解锁之前返回。

我正在使用CreateFile(FILE_FLAG_OVERLAPPED)打开一个串口,使用CreateIoCompletionPort()将其与CompletionPort相关联,使用ReadFile()WriteFile()读取/写入并使用{关闭它{1}}。

我注意到,如果我足够快地关闭并重新打开串口,我会从CloseHandle()返回ERROR_ACCESS_DENIED。尽管我正在等待CreateFile()返回,然后等待与该句柄相关的所有未完成的读/写操作从完成端口返回,这种情况仍在发生。当然有更好的方法:)

如何同步关闭串口?请不要重试循环,睡眠()或其他一些廉价的黑客攻击。

编辑:这可能与我使用完成端口和FILE_FLAG_OVERLAPPED有关。当读/写操作完成时,我得到一个回调。端口关闭是否有某种回调?

2 个答案:

答案 0 :(得分:1)

我认为问题在于为COM端口提供服务的驱动程序。因此 - 没有API可以“实际关闭”COM端口。

顺便说一下,关闭文件句柄后,无需等待所有完整的I / O完成错误。当CloseHandle返回所有未完成的I / O 已经完成/取消时,您只是异步接收回调(无论是通过完成端口还是APC队列,无论如何)。

特别是FTDI驱动程序(那些模拟COM-> USB的驱动程序)已知非常小问题。

我可能只建议在关闭句柄之前尝试刷新数据。您可以等待所有I / O完成 关闭COM端口之前(如果这适用于您的情况)。或者,您可以致电SetCommMaskWaitCommEvent以确保没有待处理的发送数据。希望这可能会有所帮助。

修改

CloseHandle是否立即(在它返回之前)取消文件句柄上的所有挂起的I / O?

严格来说 -

文件对象可能还有其他引用。例如,用户模式代码可以调用DuplicateHandle,或者内核模式驱动程序可以调用ObReferenceObjectByXXXX。在这种情况下,句柄所指的对象不一定被释放。

当最后一个句柄关闭时,将调用驱动程序DispatchCleanup。它必须根据this取消所有未完成的I / O.

然而,当一个线程在CloseHandle范围内时 - 理论上你可以从另一个线程发出另一个I / O(如果你很幸运 - 句柄仍然有效)。当您正在调用I / O函数(例如WriteFile等)时,OS会临时增加对象的引用计数器。这反过来可能会启动另一个I / O,这不会被CloseHandle调用直接取消。

但是在这种情况下,在发出新的I / O后,句柄将立即由O / S关闭,因为对象的引用计数再次达到0。

因此,在这种变态的情况下,可能会出现这样的情况,即在调用CloseHandle之后,您无法再次重新打开该文件。

答案 1 :(得分:0)

当您在线程中打开COM端口时,操作系统会打开另一个隐藏线程来执行I / O.我也试图解决关闭端口的问题。接近我可以告诉一个可行的方法是:1)挂起打开COM端口的线程,2)PurgeComm()停止所有I / O并清空所有读/写I / O缓冲区,然后3)然后尝试关闭COM端口。可能有一个waitforsingleobject涉及确定具有COM端口的线程何时实际挂起。除非绝对需要关闭COM端口,否则我正在考虑打开COM端口并让WinProc处理IDM_Exit命令来关闭COM端口,线程和应用程序。不是我想要的,而是我可以忍受的选择。我使用USB到串行端口连接,不知道这是什么问题导致我。我知道如果您使用USB到串行端口接口,则需要将引脚20置为高电平(DTR)。引脚20有助于为接口供电,但仅提供约30ma左右。如果这一切正常,我将对此帖子进行更新,并告诉您如何关闭COM端口。 Windows已经弄乱了串口驱动程序,似乎满足于让事情陷入混乱!