Linux C++: Does a Return from Main() Cause a Multithreaded App to Terminate

Linux C++: Does a return from main() cause a multithreaded app to terminate?

Yes. In modern linux (more importantly newer versions of GNU libc) exit_group is the system call used when main returns, not plain exit. exit_group is described as follows:

This system call is equivalent to
exit(2) except that it terminates not
only the calling thread, but all
threads in the calling process's
thread group.

It is worth noting that current the c++ standard makes no mention of threads, so this behavior is not c++ specific, but instead is specific to your particular implementation. That said, every implementation I've personally seen kills all threads when the main thread terminates.

EDIT: It is also worth noting Jonathan Leffler's answer which points out that the POSIX standard does indeed specify this behavior, so it is certainly normal for an application using pthreads for its threading.

EDIT: To answer the follow up about pthread_detach. Basically it is considered a resource leak if you do not join a non-detached thread. If you have a long running task which you have no need to "wait for", and it just "ends when it ends" then you should detach it which will not have a resource leak when it terminates with no join. The man page says the following:

The pthread_detach() function marks
the thread identified by thread as
detached. When a detached thread
terminates, its resources are
automatically released back to the
system without the need for another
thread to join with the terminated
thread.

So a quick and dirty answer is: "when you don't care when it ends, detach it. If another thread cares when it ends and must wait for it to terminate, then don't."

What happens to a running thread on return from main in C?

I'm sure the threads are killed, but how does this actually happen?

Returning from main is the same as calling exit(). This means handlers established by atexit(), and any system cleanup handlers are run. Finally the kernel is asked to terminate the entire process(i.e. all threads).

(Note that this might cause issues if you have other threads running at that point, e.g. another thread accessing a global C++ objects right after the runtime calls their destructors.)

When the main thread exits, do other threads also exit?

When the main thread returns (i.e., you return from the main function), it terminates the entire process. This includes all other threads. The same thing happens when you call exit. You can avoid this by calling pthread_exit.

The purpose of pthread_detach is to make it so you don't need to join with other threads in order to release their resources. Detaching a thread does not make it exist past process termination, it will still be destroyed along with all the other threads.

How to gracefully quit a multi-threaded application?

Most long running 'thread main' functions have a form a bit like the following:

while (doWork) {
work();
}

with doWork being a std::atomic<bool>.

When the main thread wants to quit, it sets myThread.doWork = false on all the threads that are still alive, which allows them to fall out when they're ready.

By calling myThread.wait() on the main thread, it blocks until the thread that you've told to stop doing work actually stops.
In doing this for all your threads, by the time the main thread leaves main() it's the only thread still running.

Side note:
if you have to await work to be pushed to it, you probably want to look into the QWaitCondition class so that you can awake your thread both when there's work and when you want it to stop.

Proper multi-thread program termination. C

So, first and foremost, we don't know what you're using for threads. You might consider using libBoost for this, as it will make your life easier with RAII style locks and whatnot.

Anyhow, only the elected thread of your process (typically main(), in most examples), will catch the signal, unless you've enabled signal masking. When you want the threads to shut down cleanly, you just need to:

  1. Wakeup the threads waiting on accept() by modifying your FD set to include a pipe that can also wake up the blocking call.
  2. Simply signal the condvars the other threads are waiting on, and set some sort of mutex-protected boolean/flag to notify the thread that it should exit early (ie: mutexLock()l; bool bExitEarly = true; signal(condVar); mutexUnlock();).
  3. Assuming you spawned the threads as joinable (ie: non-detached), just make sure you have a copy of the pointer to each thread object, and call thread_join() on each of them after you've signaled them to stop. This will ensure that the threads are fully stopped before main() exits. If you don't do this, main() could exit before the threads are done, and just forcibly kill off the threads while they are in the middle of their shutdown logic, which is messy, and could cause your program to crash or worse.

What happens to a detached thread when main() exits?

The answer to the original question "what happens to a detached thread when main() exits" is:

It continues running (because the standard doesn't say it is stopped), and that's well-defined, as long as it touches neither (automatic|thread_local) variables of other threads nor static objects.

This appears to be allowed to allow thread managers as static objects (note in [basic.start.term]/4 says as much, thanks to @dyp for the pointer).

Problems arise when the destruction of static objects has finished, because then execution enters a regime where only code allowed in signal handlers may execute ([basic.start.term]/1, 1st sentence). Of the C++ standard library, that is only the <atomic> library ([support.runtime]/9, 2nd sentence). In particular, that—in general—excludes condition_variable (it's implementation-defined whether that is save to use in a signal handler, because it's not part of <atomic>).

Unless you've unwound your stack at this point, it's hard to see how to avoid undefined behaviour.

The answer to the second question "can detached threads ever be joined again" is:

Yes, with the *_at_thread_exit family of functions (notify_all_at_thread_exit(), std::promise::set_value_at_thread_exit(), ...).

As noted in footnote [2] of the question, signalling a condition variable or a semaphore or an atomic counter is not sufficient to join a detached thread (in the sense of ensuring that the end of its execution has-happened-before the receiving of said signalling by a waiting thread), because, in general, there will be more code executed after e.g. a notify_all() of a condition variable, in particular the destructors of automatic and thread-local objects.

Running the signalling as the last thing the thread does (after destructors of automatic and thread-local objects has-happened) is what the _at_thread_exit family of functions was designed for.

So, in order to avoid undefined behaviour in the absence of any implementation guarantees above what the standard requires, you need to (manually) join a detached thread with an _at_thread_exit function doing the signalling or make the detached thread execute only code that would be safe for a signal handler, too.

terminating a thread in C

You can stop the thread using pthread_cancel:

pthread_cancel(thread1);

And in readdata:

/* call this when you are not ready to cancel the thread */
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
...
/* call this when you are ready to cancel the thread */
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);

See the pthread_cancel man page for more information - there's an example included.

If you don't want to use pthread_cancel, you can use a global flag that is set by the main thread and read by thread 1. Also, you can use any of the IPC methods, like establishing a pipe between the threads.

When the main exits where does the console output go?

When main exits it calls exit which terminates all threads, regardless detached or not. This is because exit terminates the entire process.

The C++ runtime runs main as exit(main(argc, argv)), so that returning from main causes exit to be called.

You can terminate your main thread, if you wish, by calling pthread_exit. In this case the main thread will not return from main and will not call exit. The application will keep running until some other thread calls exit or all threads terminate (or the application crashes). This is how it works on Linux, not sure about Windows.

std::cout object and the other standard streams are available at least until exit is called. These streams are initialized using Schwarz Counter idiom, which makes sure they get initialized before its first use and destroyed after the last user is gone. In other words, if you have a global object with a constructor and destructor, which gets initialized before main is entered and destroyed after (when exit is called), that standard stream is still going to be available in that global object destructor. Basically, there is a reference counter associated with each standard stream, each translation unit (object file) increments this reference counter on the startup and decrements on termination.

ISO/IEC 14882:2011(E) says:

27.4 Standard iostream objects

27.4.1.2 The objects [the standard streams] are constructed and the associations are established at some time prior to or during the first time an object of class ios_base::Init is constructed, and in any case before the body of main begins execution†. The objects are not destroyed during program execution. The results of including in a translation unit shall be as if defined an instance of ios_base::Init with static storage duration. Similarly, the entire program shall behave as if there were at least one instance of ios_base::Init with static storage duration.

Constructors and destructors for static objects can access these objects to read input from stdin or write output to stdout or stderr.



Related Topics



Leave a reply



Submit