views:

568

answers:

10

I've got a c++ Win32 app that has a number of threads that might be busy doing IO (HTTP calls, etc) when the user wants to shutdown the app. Currently, I play nicely and wait for all the threads to end before returning from main. Sometimes, this takes longer than I would like and indeed, it seems kind of pointless to make the user wait when I could just exit. However, if I just go ahead and return from main, I'm likely to get crashes as destructors start getting called while there are still threads using the objects.

So, recognizing that in an ideal, platonic world of virtue, the best thing to do would be to wait for all the threads to exit and then shutdown cleanly, what is the next best real world solution? Simply making the threads exit faster may not be an option. The goal is to get the process dead as quickly as possible so that, for example, a new version can be installed over it. The only disk IO I'm doing is in a transactional db, so I'm not terribly concerned about pulling the plug on that.

Thanks!

+2  A: 

Best way: Do your work while the app is running, and do nothing (or as close to) at shutdown (works for startup too). If you stick to that pattern, then you can tear down the threads immediately (rather than "being nice" about it) when the shutdown request comes without worrying about work that still needs to be done.

In your specific situation, you'd probably need to wait for IO to finish (writes, at least) if you're doing local work there. HTTP requests and such you can probably just abandon/close outright (again, unless you're writing something). But if it is the case that you're writing during this shutdown and waiting on that, then you may want to notify the user of that, rather than letting your process look hung while you're wrapping things up.

DannySmurf
A: 

Instruct the user to unplug the computer. Short of that, you have to abandon your asynchronous activities to the wind. Or is that HWIND? I can never remember in C++. Of course, you could take the middle road and quickly note in a text file or reg key what action was abandoned so that the next time the program runs it can take up that action again automatically or ask the user if they want to do so. Depending on what data you lose when you abandon the asynch action, you may not be able to do that. If you're interacting with the user, you may want to consider a dialog or some UI interaction that explains why its taking so long.

Personally, I prefer the instruction to the user to just unplug the computer. :)

Tyler Jensen
give a funny answer, get modded down to the abyss, it looks like... People have no sense of humor...
tloach
Yeah, I'm hurt. Maybe their stack overflowed.
Tyler Jensen
DIGG or Slashdot are thataway ----->
jim
A: 

If you want to pull the plug messily, exit(0) will do the trick.

Paul Nathan
IIRC for threaded applications, you need to call _exit() rather than exit(). I was looking for the documentation for this but I can't find it at the moment.
ceretullis
+2  A: 

I'd recommend having your GUI and work be done on different threads. When a user requests a shutdown, dismiss the GUI immediately giving the appearance that the application has closed. Allow the worker threads to close gracefully in the background.

luke
If you mean "setting main window to invisible mode" then this wouldn't fix the root problem, only being cosmetic. Besides, the question is about telling threads to stop NOW, not to hide they're still running.
Joe Pineda
+5  A: 

Use overlapped IO so that you're always in control of the threads that are dealing with your I/O and can always stop them at any point; you either have them waiting on an IOCP and can post an application level shutdown code to it, OR you can wait on the event in your OVERLAPPED structure AND wait on your 'all threads please shutdown now' event as well.

In summary, avoid blocking calls that you can't cancel.

If you can't and you're stuck in a blocking socket call doing IO then you could always just close the socket from the thread that has decided that it's time to shut down and have the thread that's doing IO always check the 'shutdown now' event before retrying...

Len Holgate
A: 

I once had a similar problem, albeit in Visual Basic 6: threads from an app would connect to different servers, download some data, perform some operations looping upon that data, and store on a centralized server the result.

Then, new requirement was that threads should be stoppable from main form. I accomplished this in an easy though dirty fashion, by having the threads stop after N loops (equivalent roughly to half a second) to try to open a mutex with a specific name. Upon success, they immediately stopped whatever they were doing and quit, continued otherwise.

This mutex was created only by the main form, once it was created all the threads would soon close themselves. The disadvantage was that user needed to manually specify it wanted to run the threads again - another button to "Enable threads to run" accomplished this by releasing the mutex :D

This trick is guaranteed to work for mutex operations are atomic. Problem is you're never sure a thread really closed - a failure in the logic of handling the "openMutex succeeded" case could mean it never ends. You also don't know when/if all the threads have closed (assuming your code is right, this would take roughly the same time it takes for the loops to stop and "listen").

With VB's "apartment" model of multi-threading it's somewhat difficult to send info from the threads to the main app back and forth, it's much easier to "fire and forget" or to send it only from the main app to the thread. Thus, the need of these kind of long-cuts. Using C++ you're free to use your multi-threading model, so these constraints might not apply to you.

Joe Pineda
A: 

Whatever you do, do NOT use TerminateThread, especially on anything that could be in OS HTTP calls. You could potentially break IE until reboot.

Change all of your IO to an asynchronous or non-blocking model so that they can watch for termination events.

+3  A: 

I use an exception-based technique that's worked pretty well for me in a number of Win32 applications.

To terminate a thread, I use QueueUserAPC to queue a call to a function which throws an exception. However, the exception that's thrown isn't derived from the type "Exception", so will only be caught by my thread's wrapper procedure.

The advantages of this are as follows:

  • No special code needed in your thread to make it 'stoppable' - as soon as it enters an alertable wait state, it will run the APC function.
  • All destructors get invoked as the exception runs up the stack, so your thread exits cleanly.

The things you need to watch for:

  • Anything doing catch (...) will eat your exception. User code should always use catch(const Exception &e) or similar!
  • Make sure your I/O and delays are done in an "alertable" way. this means calling sleepex(N, true) instead of sleep(N).
  • CPU-bound threads need to call sleepex(0,true) occasionally to check for termination

You can also 'protect' areas of your code to prevent task termination during critical sections.

Roddy
A: 

If you need to shutdown suddenly: Just call ExitProcess - which is what is going to be called just as soon as you return from WinMain anyway. Windows itself creates many worker threads that have no way to be cleaned up - they are terminated by process shutdown.

If you have any threads that are performing writes of some kind - obviously those need a chance to close their resources. But anything else - ignore the bounds checker warnings and just pull the rug from under their feet.

Chris Becke
A: 

You can call TerminateProcess - this will stop the process immediately, without notifying anyone and without waiting for anything.

Nir