views:

536

answers:

3

Hi,

Is it okay to register WSACleanup through atExit function ? We have several applications that can terminate at different points in the code so we would like to avoid putting WSACleanup everywhere throughought the code. Curently we call WSAStartup / WSACleanup through DllMain since we have a dll that is used by all these applications. However, Microsoft strictly advices against the use of WSAStartup / WSACleanup via DllMain since this can cause deadlocks. We can move WSAStarup out of DllMain and call this at one point in the code for all applications before they access the Windows sockets library. And, as soon as we call WSAStartup, we would like to use the atExit function to register a call to WSACleanup. Does anyone have any experiences with this approach ? Thanks!

+1  A: 

If you have a multi-threaded app and some of the threads are still connected, the applications at the other end may not like the way the connection is terminated. So it is preferable to close down all communication in an ordered way before main() terminates, and when you have done that, you can just as well call WSACleanup.

Pim
+1  A: 

Well I think atExit should not be used. You should follow RAII principle of wrapping of initialization and destruction of socket library in a class.

Alien01
While good style, this doesn't help one iota. From a process viewpoint, atexit() processing happens at the same time as the running of global destructors. Any issue you'd have with calling WSACleanup from AtExit, you'd likely still have whan calling it from a dtor.
MSalters
+1  A: 

I agree that the RAII approach is favourable.

However a word of warning: atExit mixed with dlls and handles is broken on windows. Unfortunately this effects RAII too as this is implemented with atExit handlers by the c++ runtime.

The order that atexit handlers are called on windows:

  1. somewhere exit is called or main() goes out of scope
  2. atexit handlers defined in the process are called.
  3. all handles are destroyed.
  4. atexit handlers defined in dlls are called.

It doesn't matter if atexit handlers in dlls are registered before handlers in the process the process handlers are called first and the handles are destroyed before the dll handlers are called. This results in win32 exceptions, when the clean up code is called as all the handles owned by dlls are no longer valid.

This effects code that holds handles to threads, mutexs, files, sockets etc. If they are allocated in a dll then they must be cleaned up before exit is called or not at all.

By the way I am not anti window, if I am wrong or anyone knows any way around this I would love to know as this causes me untold pain in application clean up. I figured this out be debugging exit handling in the c++ runtime, after getting win32 exceptions when applications exit.

I had to remove all calls to exit from my code. I now ensured that no static data in a dll controls a handle. All static handles are controlled by objects that are destructed when main goes out of scope.

iain
Not broken. If you unloaded the DLLs before the global dtors from the EXE, any dtor from the application would fail when calling a function from that dtor. The current setup allows the EXE to depend on DLLs, but not the other way around.In addition, you shouldn't open or close handles in DLLMain, that's not a new rule. AtExit processing is part of DLLMain, so it inherits those rules. A quick solution is to use smart pointers for all DLL resources. When the application cleans up its last smart pointer to a DLL resource, the DLL will know it can clean up, and this is before AtExit.
MSalters
Thanks for the note on DLLMain, I didn't realise this. Your note on the smart pointer: this will only work if it is declared in main or below and not static, right?
iain
I still do not get the correct way to do it. What if I have a DLL that provides a certain functionality. An application that loads the DLL and invokes certain functions (that internally access the Winsock API) needs to have WSAStartup called at least once. I can wrap all these functions into a class and make sure that WSAStartup is called at least once. The application can now exit at any point of time and the only way I see of calling WSACleanup is a) through atExit or b) through a global desctructor. From what I understood, both can cause problems. What is the way out of this ?
Vishal