7

我正在拉扯我的头发,试图弄清楚串行端口何时完成关闭,以便我可以重新打开它。事实证明,CloseHandle()在端口实际解锁之前返回。

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

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

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

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

4

3 回答 3

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或等)时,操作系统会暂时增加对象的引用计数器。这反过来可能会启动另一个 I/O,它不会被CloseHandle调用直接取消。

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

因此,在这种变态的情况下,可能会发生这样一种情况,即在CloseHandle您致电后立即无法再次重新打开文件。

于 2012-01-17T15:03:00.583 回答
0

在您发出 CloseHandle() 请求(可能在其他线程上)之后,确保您的读取器和写入器失败(句柄无效),然后再尝试再次触摸设备。在尝试发出另一个 CreateFile 之前,您可以使用它作为清理所有 io 处理的提示。我必须说完成端口确实看起来毫无必要的巴洛克风格。

于 2012-09-20T14:28:28.993 回答
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 把串行端口驱动程序弄得一团糟,似乎满足于让事情变得混乱!

于 2016-07-06T00:36:01.470 回答