49

C++11 introduces a new way of finishing program execution—std::quick_exit.

Quoting the N3242 18.5 (p. 461):

[[noreturn]] void quick_exit(int status) noexcept;

Effects: Functions registered by calls to at_quick_exit are called in the reverse order of their registration, except that a function shall be called after any previously registered functions that had already been called at the time it was registered. Objects shall not be destroyed as a result of calling quick_exit. If control leaves a registered function called by quick_exit because the function does not provide a handler for a thrown exception, terminate() shall be called. [ Note: at_quick_exit may call a registered function from a different thread than the one that registered it, so registered functions should not rely on the identity of objects with thread storage duration. — end note ] After calling registered functions, quick_exit shall call _Exit(status). [ Note: The standard file buffers are not flushed. See: ISO C 7.20.4.4. — end note ]

As the definition of std::abort(void) and std::_Exit(int status) differ only in ability to pass the status to the parent process, it raises my question.

Does it mean that the only difference in semantics between std::quick_exit and std::abort are that std::quick_exit calls functions registered using std::at_quick_exit and allows to set the returned status?

What was the rationale for introducing this function?

Jon Purdy
  • 53,300
  • 8
  • 96
  • 166
Rafał Rawicki
  • 22,324
  • 5
  • 59
  • 79

3 Answers3

52

There's a good write-up available here, I'll just summarize it. This feature was added to specifically deal with the difficulty of ending a program cleanly when you use threads. By nature, the exit is started by a highly asynchronous event, the user closing the user interface, the admin shutting down the machine, etcetera. This happens without regard to the state of the threads the program started, they are almost always in a highly unpredictable state.

In an ideal world, the program's main() function asks the threads to exit, typically by signaling an event, waits for the threads to end and then exits main() for a clean shutdown through exit(). That ideal is however very hard to achieve. A thread could be buried deep inside a system call, say, waiting for some I/O to complete. Or it is blocking on a synchronization object that needs to be signaled by another thread in the right order. The outcome is rarely pleasant, real programs often deadlock on exit. Or crash when the shutdown order is unexpected.

There's a simple and very tempting workaround for this problem: call _exit() instead. Kaboom, program ended, the operating system brooms up the shrapnel. But clearly without any cleanup at all, very messy sometimes with artifacts like a half-written file or an incomplete dbase transaction.

std::quick_exit() offers the alternative. Similar to _exit() but with still the option to execute some code, whatever was registered with at_quick_exit.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • 13
    Also, since `abort` signals `SIGABRT`, calling `abort` will typically result (though this is configureable) in a **core dump** on *nix, or in a popup on Windows (e.g. _Program has stopped working, Close / Debug_). Only use `abort` when terminating due to an **unexpected condition** and you want a coredump/minidump to **diagnose the reason** for the unexpected condition. – vladr Sep 17 '13 at 13:50
  • 3
    I always wish my eyes could tell what is truly important in two sentences that uses back-ticks and bold type profusely. Nope, I need a new set of eyes. Shopping recommendations appreciated. – Hans Passant Jun 09 '18 at 22:31
29

The rationale for std::quick_exit is discussed in N1327 and N2440. The key differences between quick_exit, _Exit, and exit concerns the handling of static destructors and flushing critical information to stable storage:

  • std::_Exit: doesn't execute static destructors or flush critical IO.
  • std::exit: executes static destructors and flushes critical IO.
  • std::quick_exit: doesn't execute static destructors, but does flush critical IO.

(As mentioned, std::abort just sends SIGABRT.)

一二三
  • 21,059
  • 11
  • 65
  • 74
  • 7
    I don't see any evidence in the standard that std::quick_exit flushes critical IO. In fact, the standard says "Note: The standard file buffers are not flushed." What is the basis for your belief that std::quick_exit flushes critical IO, and, for that matter, what do you mean by "critical" IO? – KnowItAllWannabe Sep 20 '12 at 22:32
  • 7
    @KnowItAllWannabe: He's defining critical as "you cared enough about it to register an `at_quick_exit` handler: – Ben Voigt Apr 10 '13 at 23:54
3

std::abort will terminate your application without calling any functions registered using "at_exit/at_quick_exit". On the other hand, std::quick_exit will, as you pointed out, call the functions registered using std::at_quick_exit.

std::abort typically aborts your application, this should be called when some abnormal situation happens and your application has to be closed without doing any cleanups. From the std::abort documentation:

Causes abnormal program termination unless SIGABRT is being caught by a signal handler passed to signal and the handler does not return.

When you want to perform some cleanups, std::quick_exit will be more appropiate. This last function also lets you stop your application gracefully, since it ends up calling std::_Exit instead of signaling a signal like std::abort(which signals SIGABRT, making the application stop abnormally).

std::exit allows you to exit your application gracefully, while still cleaning up automatic, thread local and static variables. std::quick_exit does not. That's why there is a "quick_" in its name, it's faster since it skips the clean up phase.

Therefore, there is an actual semantic difference between both functions. One stops the application abnormally, and the other performs a gracefull exit, allowing you to do some clean ups.

mfontanini
  • 21,410
  • 4
  • 65
  • 73
  • 1
    And that is still unresolved - why allow to do some cleanups and not all, when the termination is made "gracefully"? I've never seen `quick_exit` in a real code, but if I got it in the code review, I'd be, probably, tempted to ask for making it complete cleanup or nothing. Are there any WG21 sources about this? – Rafał Rawicki Mar 18 '12 at 13:23
  • If you want complete cleanup, then you would use "exit". quick_exit is faster, since it does not call any automatic, thread local and static variables' desctructor. I believe it would be better to compare std::quick_exit with std::exit, since both of them allow the user to perform a gracefull close, while std::abort basically terminates your application abnormally. – mfontanini Mar 18 '12 at 13:29
  • 6
    C++ destructors commonly do things (like free memory) that aren't necessary when the process is exiting (because the OS will do it). I guess that `quick_exit` allows you to do some cleanup, but leave the rest to the OS. – Roger Lipscombe Mar 18 '12 at 13:30
  • 1
    `std::exit` doesn't do anything for variables with automatic duration. Stack unwinding from an exception that is ultimately caught in `main` is more appropriate for that. – Luc Danton Mar 18 '12 at 15:44