我绞尽脑汁想弄清楚串行端口何时完成关闭,以便我可以重新打开它。事实证明,CloseHandle()
在端口实际解锁之前返回。
我正在使用 CreateFile(FILE_FLAG_OVERLAPPED)
打开一个串行端口,使用 CreateIoCompletionPort()
将其与 CompletionPort 相关联,使用 ReadFile( )
、WriteFile()
并使用 CloseHandle()
关闭它。
我注意到,如果我足够快地关闭并重新打开串行端口,我会从 CreateFile()
返回一个 ERROR_ACCESS_DENIED
。尽管我正在等待 CloseHandle()
返回,然后等待与该句柄关联的所有未完成读/写操作从完成端口返回,但这种情况仍在发生。当然有更好的方法:)
如何同步关闭串行端口?请不要重试循环、sleep() 或其他一些廉价的技巧。
编辑:也许这与我使用完成端口和 FILE_FLAG_OVERLAPPED 有关。当读/写操作完成时,我得到一个回调。端口关闭是否有某种回调?
最佳答案
我认为问题出在服务于 COM 端口的驱动程序上。因此 - 将没有 API 来“实际关闭”COM 端口。
顺便说一句,关闭文件句柄后,无需等待所有未完成的 I/O 完成并出现错误。当 CloseHandle
返回时,所有未完成的 I/O 都已经完成/取消,您只需异步接收回调(无论是通过完成端口还是 APC 队列)。
特别是 FTDI 驱动程序(那些模拟 COM->USB 的驱动程序)众所周知是非常有问题的。
我可能只建议在关闭句柄之前尝试刷新数据。您可以等待所有 I/O 完成然后关闭 COM 端口(如果这适用于您的情况)。或者,您可以调用 SetCommMask
和 WaitCommEvent
以确保没有待处理的发送数据。希望这可能有所帮助。
编辑:
CloseHandle
是否会立即(在返回之前)取消文件句柄上所有未决的 I/O?
严格来说 - 不。
可能还有其他对文件对象的引用。例如,用户模式代码可以调用 DuplicateHandle
,或者内核模式驱动程序可以调用 ObReferenceObjectByXXXX
。在这种情况下,句柄所指的对象不一定会被释放。
当最后一个句柄关闭时,将调用驱动程序的 DispatchCleanup
。它必须根据 this 取消所有未完成的 I/O。 .
然而,当一个线程在 CloseHandle
中时 - 理论上您可以从另一个线程发出另一个 I/O(如果幸运的话 - 句柄仍然有效)。当您调用 I/O 函数(例如 WriteFile
等)时,操作系统会暂时增加对象的引用计数器。这反过来可能会启动另一个 I/O,它不会被 CloseHandle
调用直接取消。
然而在这种情况下,句柄将在发出新的 I/O 后立即被 O/S 关闭,因为对象的引用计数再次达到 0。
因此在这种变态的情况下,可能会发生这样的情况,即在调用 CloseHandle
之后您无法再次重新打开文件。
关于windows - CloseHandle() 在串口实际关闭之前返回,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8885748/