可以通过 atExit 函数注册 WSACleanup 吗?我们有几个应用程序可以在代码中的不同点终止,因此我们希望避免将 WSACleanup 放在代码中的任何地方。目前我们通过 DllMain 调用 WSAStartup / WSACleanup,因为我们有一个所有这些应用程序都使用的 dll。但是,Microsoft 严格建议不要通过 DllMain 使用 WSAStartup / WSACleanup,因为这会导致死锁。我们可以将 WSAStarup 移出 DllMain,并在所有应用程序访问 Windows 套接字库之前在代码中的某一点调用它。而且,一旦我们调用 WSAStartup,我们就想使用 atExit 函数来注册对 WSACleanup 的调用。有没有人有这种方法的经验?谢谢!
3 回答
如果您有一个多线程应用程序并且某些线程仍然连接,那么另一端的应用程序可能不喜欢连接终止的方式。因此,最好在 main() 终止之前以有序的方式关闭所有通信,当您完成此操作后,您也可以调用 WSACleanup。
我同意 RAII 方法是有利的。
然而,一个警告:atExit 与 dll 和句柄混合在 Windows 上被破坏了。不幸的是,这也会影响 RAII,因为这是由 c++ 运行时使用 atExit 处理程序实现的。
在 Windows 上调用 atexit 处理程序的顺序:
- 某处 exit 被调用或 main() 超出范围
- 调用进程中定义的 atexit 处理程序。
- 所有的句柄都被破坏了。
- 调用 dll 中定义的 atexit 处理程序。
如果 dll 中的 atexit 处理程序在进程中的处理程序之前注册并不重要,首先调用进程处理程序并在调用 dll 处理程序之前销毁句柄。这会导致 win32 异常,当调用清理代码时,因为 dll 拥有的所有句柄都不再有效。
这会影响保存线程、互斥体、文件、套接字等句柄的代码。如果它们是在 dll 中分配的,则必须在调用 exit 之前清理它们或根本不清理它们。
顺便说一句,我不是反窗口,如果我错了,或者有人知道任何解决方法,我很想知道,因为这给我在应用程序清理带来了难以言喻的痛苦。在应用程序退出时获得 win32 异常后,我发现这是在 c++ 运行时调试退出处理。
我必须删除所有调用才能从我的代码中退出。我现在确保 dll 中没有静态数据控制句柄。所有静态句柄都由在 main 超出范围时被破坏的对象控制。
好吧,我认为不应使用 atExit 。您应该遵循将套接字库的初始化和销毁包装在一个类中的 RAII 原则。