Thanks, Jonathan, for your detailed answer. Ashish
On Fri, Dec 30, 2011 at 1:41 PM, Jonathan M Davis <[email protected]> wrote: > On Friday, December 30, 2011 10:45:43 Ashish Myles wrote: >> Ok, now there are two issues here: >> IMPLEMENTATION: Implementation of a safe_exit() without an explicit >> Exception seems to be easy to do at the language level for a >> single-threaded program -- you simply have a hidden/system class like, >> say, __SystemException from which Exception derives that be comes the >> base class of all throwable objects. __ExitException could then >> derive from __SystemException and store the exit value. But it is not >> clear how this would work for multithreaded programs, with which I >> have little experience in the context of C++ exceptions. Presumably, >> the __ExitException would have to be thrown in all threads and could >> interrupt functions that would otherwise not throw exceptions -- I >> can't say I understand all the implications. > > It's more complicate than that. The base class of all throwable objects is > Throwable. Error and Exception are derived from Throwable. Destructors, > finally > blocks, and scope statements are all skipped when a Throwable is thrown unless > it is derived from Exception. So, there is no proper cleanup unless an > Exception is thrown. Right now, the compiler, the runtime, and programmers can > all assume that > > try > { > //code > //1 > } > catch(Exception e) > { > //2 > } > > either #1 or #2 will be hit in that code if proper cleanup is occuring. In > fact nothrow relies on this. If you wrap a function call in a try-catch block > which catches Exception, then the function it's called in can be nothrow even > if the function being called throws an exception. If we tried to have another > exception type which was for exiting, then you'd get this weird situation > where nothrow functions _can_ throw when the program is being shutdown > properly, and that could be a big problem. > > Functions in D are set up around the idea that the only way to exit a function > and have proper cleanup occur is to either return from it or have an Exception > thrown from it. You're trying to have another way added. It's not that it's > necessarily impossible, but it would likely require the redesign of several > features and would break the assumptions made by a lot of code. > >> For cleanup that needs to be done no matter what the exception, I >> would just use a finally{} block. > > Yes and no. finally gets hit whether an Exception is thrown or the try block > is > exited normally, but it isn't run when a non-Exception Throwable (generally an > Error) is thrown, so it gurantees nothing on unsafe shutdown. And if you were > using exit, what would be the proper behavior? Neither the remainder of the > try block nor the catch block would be run (since exit would skip the rest of > the try block and skip the catch block entirely), which would likely break the > assumptions made by a lot of code. It would certainly break scope. All of a > sudden, you have something other than Error which won't hit scope(success) or > scope(failure) but _will_ hit scope(exit), and that something is trying to be > exiting _cleanly_ - unlike Error. > >> UTILITY: Now, the actual utility of having a safe exit seems to be in >> question here. A common use of this is in OpenGL programs (that may be >> implicitly multithreaded) where the keyboard handler exit()s when I >> hit 'q' or ESC (which is quite common). Moreover, the underlying GUI >> framework or other APIs being used may conceivably have multiple >> threads and abstract this out for the user. Is this an unreasonable >> use case for a safe exit? Or would this be too difficult to implement >> cleanly? > > Exceptions only affect a single thread, so they're not going to help you > terminate a multi-threaded program regardless. And to terminate another > thread, you need a way to terminate it. The only ways to do that are to tell > them to terminate themselves or to kill them. There is no way that I'm aware > of built into threads to tell them that it's time to shutdown and then let > them do it cleanly (which is what you'd need for a clean shutdown). You could > use std.concurrency to inform them to shutdown or have a shared flag which > indicates that it's time for all threads to shutdown, but you couldn't use > pthreads or the Windows equivalent to tell a thread to shutdown cleanly. So, > the only means generally available to terminate a thread is to forcibly kill > it (as C's exit does), making automatic cleanup impossible. > > _Some_ cleanup can be done when exit is called using atexit and on_exit, but > the stack won't be unwound properly, so RAII, scope statements, and finally > blocks aren't going to be run properly. So, critical, global stuff can be > potentially cleaned up, but you can't get a fully clean shutdown without > actually returning or having an Exception thrown from every function in every > thread. > > So, in general, the best way to handle taking down a multi-threaded > application cleanly is to message each thread (be it via std.concurrency or a > flag or whatever) which isn't going to shutdown on its own (e.g. after > finishing > some calculation) that it needs to shutdown, wait for all threads to shutdown, > and then terminate the program by exiting main. Whether that's always possible > when dealing with C libraries, I don't know, but I believe that that's really > the only way to actually get a fully clean shutdown of a multi-threaded > program in either C++ or D. In some cases, you may be able to cleanly shutdown > most of the program and then be forced to use exit due to C stuff that you > have > no control over, but without at least shutting down the parts that you can > cleanly, the D stuff in general isn't going to shut down cleanly. > > Now, it could be that your D program will be just fine even if it isn't > shutdown cleanly (e.g. it's not like you're going to get memory lost from your > system or whatnot), but that depends on what your program is doing and what > clean up gets skipped when exit is called. In general though, exiting by > returning from main is by far the best way to exit a program and the only way > that you can do so 100% cleanly. > > - Jonathan M Davis
