I'm reading Alexandrescu's Modern C++ Design and there seems to be an
implicit understanding that thread safety is irrelevant at this point
(as seen in SingletonHolder<...>::DestroySingleton()).
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Nope. It has nothing to say about threads.
> In other words does the function I send to
> atexit() have to be thread safe?
Nope. That is implementation detail.
Stephen Howe
No, the standard doesn't address multithreading at all.
> In other words does the function I send to atexit() have to be thread
> safe?
<snip>
Ask your implementor. I would expect only one thread to be running but this
might not be guaranteed in all implementations.
> The standard defines that atexit() will call the functions registered
> at program termination. Is it specified how many threads will be
> active at such a time? In other words does the function I send to
> atexit() have to be thread safe?
The standard does not specify anything at all about threads. At this
time, standard C++ neither defines nor supports multiple threads of
operation. The C++ "abstract machine" is defined as existing in a
universe consisting almost entirely of itself, with very limited
exception for signals. This may or may not change in a future version
of the C++ standard.
> I'm reading Alexandrescu's Modern C++ Design and there seems to be an
> implicit understanding that thread safety is irrelevant at this point
> (as seen in SingletonHolder<...>::DestroySingleton()).
At present, the only answers available for your question are
completely dependent on the compiler and underlying operating system,
and you need to ask in an appropriate platform specific group for each
system of interest.
--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
> The standard defines that atexit() will call the functions registered
> at program termination. Is it specified how many threads will be
> active at such a time? In other words does the function I send to
> atexit() have to be thread safe?
The C and the C++ standards do not recognize the existance of threads,
as such, and so do not address the question. So it depends on the
implementation. My impression (although I've not verified) is that most
implementations do nothing in exit concerning threads; any threads that
are still active continue to run, right through the exit, and until exit
calls the system level process termination routine (_exit under Unix,
TerminateProcess ? under Windows).
There's a definite reason why I haven't verified this, of course. I
consider it a matter of good programming practice to terminate all user
threads before calling exit (or returning from main). As a rule, main
will start all of the application threads (after having ensured any
necessary initializations), then join on them (pthread_join under Unix,
??? under Windows) until all have finished. Whichever thread interprets
the command to exit will notify all other threads to quit; each thread
will then clean-up and return. Note that I do *not* use pthread_exit or
ExitThread; I always wind down the stack of each thread (possibly using
exceptions). Only once I have reaped all of the threads do I return
from main.
Fundamentally, unless you do this, you cannot be sure that all resources
have been freed, and you cannot know what the return status should be.
(An error in cleaning up could have an impact on the return status.)
--
James Kanze GABI Software mailto:ka...@gabi-soft.fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16
No. The standard doesn't mention threads at
all. You need to refer to your platform's
documentation.
Schobi
--
Spam...@gmx.de is never read
I'm Schobi at suespammers dot org
"Sometimes compilers are so much more reasonable than people."
Scott Meyers
>The standard defines that atexit() will call the functions registered
>at program termination. Is it specified how many threads will be
>active at such a time? In other words does the function I send to
>atexit() have to be thread safe?
The standard doesn't say anything about threads. A common real-world
approach defines a primary thread which initializes globals, executes
the main() function, and destroys globals and local statics that were
initialized and runs atexit functions after main() has returned. It is
usually a mistake to allow secondary threads to continue to run while
the environment in which they're running is being taken down all
around them. Thus, you should prevent this by joining with all your
secondary threads before returning from main() or calling exit(). IOW,
your program should be designed like this:
before main - single-threaded
main - may become multithreaded
after main - single-threaded
--
Doug Harrison
d...@mvps.org
It is ExitProcess. Even if exit() intended to do something about threads it
couldn't. The CRT may have no knowlege of all the threads present in the
process.
> There's a definite reason why I haven't verified this, of course. I
> consider it a matter of good programming practice to terminate all
> user threads before calling exit (or returning from main). As a
> rule, main will start all of the application threads (after having
> ensured any necessary initializations), then join on them
> (pthread_join under Unix, ??? under Windows) until all have
> finished.
This assumes all threads in the process are started by or known to main. In
a modern multi-component application this may not be the case. Even a simple
Windows application that uses sockets or COM will have threads which are not
known to main() or any other application code.
> Whichever thread interprets the command to exit will
> notify all other threads to quit; each thread will then clean-up
> and return. Note that I do *not* use pthread_exit or ExitThread; I
> always wind down the stack of each thread (possibly using
> exceptions). Only once I have reaped all of the threads do I
> return from main.
>
> Fundamentally, unless you do this, you cannot be sure that all
> resources have been freed, and you cannot know what the return
> status should be. (An error in cleaning up could have an impact on
> the return status.)
It is even worse. If a thread is running after the CRT has been cleaned up
by exit(), it may try to call some CRT facility which would usually result
in an invalid memory access or such. Another variant of this problem happens
when an unknown foreign thread invokes some callback into application code
after exit() or return from main(). By that time the process is shutting
down, debugger may be gone and all that is left is a cryptic core dump.
The only solution is to religiously close, shutdown, cleanup and free
everything before returning from main(). A corollary to this is that exit()
is a very bad idea in a multi-component application (unless all components
are assigned an atexit() cleanup handler either directly or through global
object destructors).
--
Eugene
> >> The standard defines that atexit() will call the functions
> >> registered at program termination. Is it specified how many threads
> >> will be active at such a time? In other words does the function I
> >> send to atexit() have to be thread safe?
> > The C and the C++ standards do not recognize the existance of
> > threads, as such, and so do not address the question. So it depends
> > on the implementation. My impression (although I've not verified)
> > is that most implementations do nothing in exit concerning threads;
> > any threads that are still active continue to run, right through the
> > exit, and until exit calls the system level process termination
> > routine (_exit under Unix, TerminateProcess ? under Windows).
> It is ExitProcess.
That's not what the documentation says. The documentation says that
ExitProcess provides a clean process shutdown. The low level routine
I'm talking about is what ExitProcess would call once it finished its
cleanup.
The documentation of ExitProcess doesn't say anything about atexit. It
would be nice to know if the functions registered with atexit are called
before or after all of the threads have been shut down. (In fact, I
find a _exit function which corresponds closely to _exit under Unix.)
More generally, it isn't clear to me what the relationship is between
ExitProcess/TerminateProcess and exit/_exit is.
> Even if exit() intended to do something about threads it couldn't.
> The CRT may have no knowlege of all the threads present in the
> process.
I don't know what you mean by the CRT, but somewhere, someone must know
all of the threads, just as somewhere, someone knows all of the open
files. Given this, it shouldn't be difficult to provide a clean
interface to shut them down.
> > There's a definite reason why I haven't verified this, of course. I
> > consider it a matter of good programming practice to terminate all
> > user threads before calling exit (or returning from main). As a
> > rule, main will start all of the application threads (after having
> > ensured any necessary initializations), then join on them
> > (pthread_join under Unix, ??? under Windows) until all have
> > finished.
> This assumes all threads in the process are started by or known to
> main.
Directly or indirectly, a thread can only be started by main or by the
constructor of a static object. You do have a point, though; I can
think of scenarios where it would be quite reasonable for a plugin to
start threads of its own through constructors of its static objects.
> In a modern multi-component application this may not be the case. Even
> a simple Windows application that uses sockets or COM will have
> threads which are not known to main() or any other application code.
There is a definite problem when you are not master of all of the code.
If you are writing a C++ application, of course, you will use some sort
of thread object, which will enrole itself with some global list of
threads and provide the necessary facilities for a clean shut-down. But
there is no such standard object, and you cannot reasonably expect third
party software to derived from YOUR thread class.
I'm not sure what the best solution is here. Ideally, this might be a
good candidate for standardization. Provided we can find some consensus
as to what it should and should not support.
> > Whichever thread interprets the command to exit will notify all
> > other threads to quit; each thread will then clean-up and return.
> > Note that I do *not* use pthread_exit or ExitThread; I always wind
> > down the stack of each thread (possibly using exceptions). Only
> > once I have reaped all of the threads do I return from main.
> > Fundamentally, unless you do this, you cannot be sure that all
> > resources have been freed, and you cannot know what the return
> > status should be. (An error in cleaning up could have an impact on
> > the return status.)
> It is even worse. If a thread is running after the CRT has been
> cleaned up by exit(), it may try to call some CRT facility which would
> usually result in an invalid memory access or such.
You'll have to explain to me what you mean by CRT. The only meaning I
know of that acronym is cathode ray tube, which doesn't make any sense
in the context you are using it.
At any rate, there is a question of what returning from main should mean
in a multithreaded context. Normally, returning from main means calling
exit, which means cleaning up and terminating. IMHO, cleaning up
implies notifying all threads that they should terminate, and waiting
for them to do so. Except that that isn't what happens in the one
system I'm familiar with (Posix) -- the threads just keep on merrily
working, exactly like you describe, potentially accessing resources that
don't exist any more. So the solution in the applications I've worked
on has always been the same: pthread_join on all threads before
stopping. (Typically, this is done by some sort of thread base class --
main doesn't explicitly know all of the threads that have been created,
but it does have access to an interface where they are registered, and
which provides a means of notification and a way of waiting on the
termination.)
> Another variant of this problem happens when an unknown foreign thread
> invokes some callback into application code after exit() or return
> from main(). By that time the process is shutting down, debugger may
> be gone and all that is left is a cryptic core dump. The only
> solution is to religiously close, shutdown, cleanup and free
> everything before returning from main(). A corollary to this is that
> exit() is a very bad idea in a multi-component application (unless all
> components are assigned an atexit() cleanup handler either directly or
> through global object destructors).
I think that we are basically in agreement. A thread should terminate
by returning from its top level function, rather than be calling
pthread_exit or its windows equivalent, and a process should terminate
by returning from main, rather than by calling exit or any similar
function.
--
James Kanze GABI Software mailto:ka...@gabi-soft.fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
When MS documentation says clean it is in the context of Win32. Basically
ExitProcess will notify all the DLLs about the shutdown and do some other OS
specific cleanup tasks. The C/C++ Run Time (CRT) is absolutely ignorant of
these activities since it is not a part of the OS as is the case on Unix.
To clean the C library stuff you must call exit() which after doing its
cleanup will invoke ExitProcess.
> The documentation of ExitProcess doesn't say anything about atexit.
> It would be nice to know if the functions registered with atexit are
> called before or after all of the threads have been shut down. (In
> fact, I find a _exit function which corresponds closely to _exit
> under Unix.)
Since Win32 is absolutely ignorant of C(++) language it has no support for
atexit(). To make the exit handlers run one needs to use C level primitives
such as exit().
> More generally, it isn't clear to me what the relationship is between
> ExitProcess/TerminateProcess and exit/_exit is.
TerminateProcess is a debugging aid that should never ever be called in
normal code. It kills the process outright without giving anyone a chance to
clean up anything.
ExitProcess is the normal Win32 way of cleanly exiting a process that is
written in assembly or in "C without the standrd library". ExitProcess will
also kill all the threads in the process but this not in a clean way.
exit() is a C(++) function that provides a way to cleanly shut down the C
standard library and then the process. Basically the same happens on return
from main().
Note that even though ExitProcess kills all threads there still is a window
of time between C library "death" and thread termination so it doesn't solve
anything for C applications.
>> Even if exit() intended to do something about threads it couldn't.
>> The CRT may have no knowlege of all the threads present in the
>> process.
>
> I don't know what you mean by the CRT, but somewhere, someone must
> know all of the threads, just as somewhere, someone knows all of the
> open files. Given this, it shouldn't be difficult to provide a clean
> interface to shut them down.
You can enumerate all user mode threads of course but this isn't really
usefull. Having knowledge about a thread doesn't allow to shut it down
cleanly. The most you can do is to kill it without real cleanup.
If the software is composed from components written in many languages the
C++ only standard won't help. This should be the task for a platform ABI.
>>> Whichever thread interprets the command to exit will notify all
>>> other threads to quit; each thread will then clean-up and return.
>>> Note that I do *not* use pthread_exit or ExitThread; I always wind
>>> down the stack of each thread (possibly using exceptions). Only
>>> once I have reaped all of the threads do I return from main.
>
>>> Fundamentally, unless you do this, you cannot be sure that all
>>> resources have been freed, and you cannot know what the return
>>> status should be. (An error in cleaning up could have an impact on
>>> the return status.)
>
>> It is even worse. If a thread is running after the CRT has been
>> cleaned up by exit(), it may try to call some CRT facility which
>> would usually result in an invalid memory access or such.
>
> You'll have to explain to me what you mean by CRT. The only meaning I
> know of that acronym is cathode ray tube, which doesn't make any sense
> in the context you are using it.
It is so common in Windows world that I forgot it isn't universal ;-) In
case you are reading piecewise it is C/C++ Run Time library.
> At any rate, there is a question of what returning from main should
> mean in a multithreaded context. Normally, returning from main means
> calling exit, which means cleaning up and terminating. IMHO,
> cleaning up implies notifying all threads that they should terminate,
> and waiting for them to do so. Except that that isn't what happens
> in the one system I'm familiar with (Posix) -- the threads just keep
> on merrily working, exactly like you describe, potentially accessing
> resources that don't exist any more. So the solution in the
> applications I've worked on has always been the same: pthread_join on
> all threads before stopping. (Typically, this is done by some sort
> of thread base class -- main doesn't explicitly know all of the
> threads that have been created, but it does have access to an
> interface where they are registered, and which provides a means of
> notification and a way of waiting on the termination.)
Threading is also intermixed with dynamic loading. For example if you unload
all dynamic libraries then you need to shut down its threads prior to that.
I guess if someone wants to define what happens on exit he should handle
both issues simultaneously.
>> Another variant of this problem happens when an unknown foreign
>> thread invokes some callback into application code after exit() or
>> return from main(). By that time the process is shutting down,
>> debugger may be gone and all that is left is a cryptic core dump.
>> The only solution is to religiously close, shutdown, cleanup and free
>> everything before returning from main(). A corollary to this is that
>> exit() is a very bad idea in a multi-component application (unless
>> all components are assigned an atexit() cleanup handler either
>> directly or through global object destructors).
>
> I think that we are basically in agreement. A thread should terminate
> by returning from its top level function, rather than be calling
> pthread_exit or its windows equivalent, and a process should terminate
> by returning from main, rather than by calling exit or any similar
> function.
Agreed.
--
Eugene
Windows equivalent and lack of "POSIX.C++" standard aside for a
moment, pthread_exit() (and thread cancellation) results in the
exception (stack unwinding) in C++. There's nothing wrong with
respect to calling pthread_exit() on any reasonable POSIX system
which also supports threaded C++ in a non-braindamaged manner,
so to say.
> and a process should terminate
> by returning from main, rather than by calling exit or any similar
> function.
You can terminate the main thread by calling pthread_exit (or
cancelling it [note that thread cancel delivery has the effect
of pthread_exit(PTHREAD_CANCELED)]) and simply rely on implicit
exit(0) invocation ("passive exit") on last thread termination.
(well, things like error checked flushing and closing of stdio
stuff aside for a moment ;-) )
regards,
alexander.
> Windows equivalent and lack of "POSIX.C++" standard aside for a
> moment, pthread_exit() (and thread cancellation) results in the
> exception (stack unwinding) in C++.
According to who? The C++ standard doesn't say so, since it doesn't
know about threads. The Posix standard doesn't say so, since it doesn't
know about C++.
The "logical" solution for an implementor would be to base himself on
the existing -- pthread_exit() in C++ works with respect to a thread as
does exit() with respect to a process. And exit() doesn't do any stack
unwinding.
> There's nothing wrong with respect to calling pthread_exit() on any
> reasonable POSIX system which also supports threaded C++ in a
> non-braindamaged manner, so to say.
I'm just curious: how do you justify the fact that pthread_exit behaves
differently with regard to a thread than exit with regard to a process?
The clean-up mechanism forseen for both uses call-backs, and not stack
walkback and destructors: atexit for exit, and
pthread_cleanup_push/pthread_cleanup_pop for pthread_exit. I'm not
saying that what you suggest wouldn't be a good idea, but it doesn't
seem to correspond very well to "existing practice". Note that the C++
committee did not think it necessary to require stack walkback in the
case of exit().
> > and a process should
> > terminate by returning from main, rather than by calling exit or any
> > similar function.
> You can terminate the main thread by calling pthread_exit (or
> cancelling it [note that thread cancel delivery has the effect of
> pthread_exit(PTHREAD_CANCELED)]) and simply rely on implicit exit(0)
> invocation ("passive exit") on last thread termination. (well, things
> like error checked flushing and closing of stdio stuff aside for a
> moment ;-) )
The problem which has been raised by Eugene Gershnik is that there are
threads that don't terminate, and that you cannot easily find and
terminate yourself. A example might be the GUI event handler thread;
typically, it will be buried somewhere deep in the GUI library, where
you cannot know about it, and all too often, there will be no way to
terminate it. So unless you either call exit() or return from main, the
program will never terminate.
--
James Kanze GABI Software mailto:ka...@gabi-soft.fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
> >> It is ExitProcess.
This sounds reasonable. The Unix model is that there isn't any OS
specific clean-up in the user process, so basically, all you have is
exit, and _exit (which is the equivalent of TerminateProcess). I was
having trouble seeing where ExitProcess fit in, but now that you've
explained it, it is clear. (Sort of -- I'm not sure why you would have
to "unload" DLL's. But the Windows DLL model is quite different from
the Unix model I am familiar with, so I will just have to accept that
you do:-).)
> > The documentation of ExitProcess doesn't say anything about atexit.
> > It would be nice to know if the functions registered with atexit are
> > called before or after all of the threads have been shut down. (In
> > fact, I find a _exit function which corresponds closely to _exit
> > under Unix.)
> Since Win32 is absolutely ignorant of C(++) language it has no support
> for atexit(). To make the exit handlers run one needs to use C level
> primitives such as exit().
Or return from main. IMHO, a C++ program should never call exit()
explicitly, as that skips calling the destructors for on stack objects.
But of course, returning from main results in exit() being called.
> > More generally, it isn't clear to me what the relationship is
> > between ExitProcess/TerminateProcess and exit/_exit is.
> TerminateProcess is a debugging aid that should never ever be called
> in normal code. It kills the process outright without giving anyone a
> chance to clean up anything.
Like _exit() under Unix. An abort() without the core dump, more or
less.
> ExitProcess is the normal Win32 way of cleanly exiting a process that
> is written in assembly or in "C without the standrd library".
> ExitProcess will also kill all the threads in the process but this not
> in a clean way. exit() is a C(++) function that provides a way to
> cleanly shut down the C standard library and then the process.
> Basically the same happens on return from main(). Note that even
> though ExitProcess kills all threads there still is a window of time
> between C library "death" and thread termination so it doesn't solve
> anything for C applications.
In some, we're back to the same situation as in Unix:-). First, the
C/C++ library (and user defined destructors for static objects) get
called, in some particular order, and THEN the various system functions,
like threads, are shut down. Unless the user takes explicit action on
his own before returning from main, threads are likely to continue
executing after critical resources that they use have ceased to exist.
Which brings us back to my original thesis: a well written program
shouldn't return from main (or call exit) before having cleanly shut
down all of the threads. Explicitly, since the system doesn't help
here. Your contribution, summed up very succinctly, was to point out
that in practice, this isn't always possible -- which is regrettably all
too true, and not just under Windows. If nothing else, threads started
by things like plug-ins will probably have a life of their own, and I
would not be surprised if some of the threads in a GUI management didn't
behave similarly.
It's interesting to look at Java with regards to this. In Java, the
process doesn't terminate when you finish main; it terminates when the
last thread terminates. (Finishing main terminates the start-up thread,
and thus the process if no other threads have been started.) Except
that this doesn't apply to all threads -- you can declare a thread to be
a daemon, in which case, the fact that it is still running doesn't
prevent the process from terminating. (Presumably, Java has the same
problem of a thread accessing inexistant ressources in the case of a
daemon thread, or if the application calls exit.)
> >> Even if exit() intended to do something about threads it couldn't.
> >> The CRT may have no knowlege of all the threads present in the
> >> process.
> > I don't know what you mean by the CRT, but somewhere, someone must
> > know all of the threads, just as somewhere, someone knows all of the
> > open files. Given this, it shouldn't be difficult to provide a
> > clean interface to shut them down.
> You can enumerate all user mode threads of course but this isn't
> really usefull. Having knowledge about a thread doesn't allow to shut
> it down cleanly. The most you can do is to kill it without real
> cleanup.
Quite. In the applications I've written (mostly large scale servers),
we've generally been master of most of the threads, and arranged to
clean them up correctly. Although now that I think of it, I think that
the data base (SyBase or Oracle) had some threads of its own, of which
we weren't master. I'm not sure what ressources they might use,
however. (We do ensure that all of the callbacks were deenregistered
before returning from main.)
In theory, Unix has a cancellation mechanism which should be able to be
used for this. I'm not that familiar with it, however, since I've never
had to use it, so I don't know how well it works in practice.
[...]
> > There is a definite problem when you are not master of all of the
> > code. If you are writing a C++ application, of course, you will use
> > some sort of thread object, which will enrole itself with some
> > global list of threads and provide the necessary facilities for a
> > clean shut-down. But there is no such standard object, and you
> > cannot reasonably expect third party software to derived from YOUR
> > thread class.
> > I'm not sure what the best solution is here. Ideally, this might be
> > a good candidate for standardization. Provided we can find some
> > consensus as to what it should and should not support.
> If the software is composed from components written in many languages
> the C++ only standard won't help. This should be the task for a
> platform ABI.
And a standard interface to it at the C++ level? (Of course, if you're
loading dynamic objects and running multi-threaded, you're already so
far outside of just C++ that a little more probably won't hurt much.)
[...]
> > At any rate, there is a question of what returning from main should
> > mean in a multithreaded context. Normally, returning from main
> > means calling exit, which means cleaning up and terminating. IMHO,
> > cleaning up implies notifying all threads that they should
> > terminate, and waiting for them to do so. Except that that isn't
> > what happens in the one system I'm familiar with (Posix) -- the
> > threads just keep on merrily working, exactly like you describe,
> > potentially accessing resources that don't exist any more. So the
> > solution in the applications I've worked on has always been the
> > same: pthread_join on all threads before stopping. (Typically, this
> > is done by some sort of thread base class -- main doesn't explicitly
> > know all of the threads that have been created, but it does have
> > access to an interface where they are registered, and which provides
> > a means of notification and a way of waiting on the termination.)
> Threading is also intermixed with dynamic loading. For example if you
> unload all dynamic libraries then you need to shut down its threads
> prior to that. I guess if someone wants to define what happens on
> exit he should handle both issues simultaneously.
This is the second time you've mentionned unloading dynamic objects.
Obviously, if you unload a dynamic object, you must make sure that no
one uses any of the ressources it contains after it has been unloaded.
But most of the time, at least in the applications I've seen, once a
dynamic object has been loaded, it stays loaded until program
termination. There are only a very few, and very controlled cases where
one would unload a dynamic object.
--
James Kanze GABI Software mailto:ka...@gabi-soft.fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
Windows DLLs are not shared libraries even though they are often used as
such. I think DLLs should probably be described as plug-ins. In particular a
DLL has a well-defined entry point that is notified when it is loaded and
unloaded. It may have its own private C/C++ runtime library completely
distinct from the one of the host process. In some ways DLLs are similar to
the result of -Bsymbolic on Unix. On the other hand DLLs can approximate
shared libraries when they use a DLL version of CRT shared with the host. In
any case one consequence of this model is that a DLL may have its own
resources (like global variables) that are completely unknown and
inaccessible to the host. When the host dies the OS has to notify the DLL to
give it a chance to cleanup the resources.
The Microsoft's C/C++ runtime goes through some very complicated gyrations
to hide all this complexity from a casual user but it is still there. On MS
newsgroups you can frequently see someone with a problem that resulted from
incorrect destruction order, mixing of one module's new with another's
delete etc.
>> TerminateProcess is a debugging aid that should never ever be
>> called in normal code. It kills the process outright without
>> giving anyone a chance to clean up anything.
>
> Like _exit() under Unix. An abort() without the core dump, more or
> less.
MS also provides _exit() in its C library. The semantics is a little
different though. This function effectively just calls ExitProcess without
cleaning the C runtime.
> Which brings us back to my original thesis: a well written program
> shouldn't return from main (or call exit) before having cleanly shut
> down all of the threads. Explicitly, since the system doesn't help
> here. Your contribution, summed up very succinctly, was to point out
> that in practice, this isn't always possible -- which is regrettably
> all too true, and not just under Windows. If nothing else, threads
> started
> by things like plug-ins will probably have a life of their own, and I
> would not be surprised if some of the threads in a GUI management
> didn't behave similarly.
>
> It's interesting to look at Java with regards to this. In Java, the
> process doesn't terminate when you finish main; it terminates when the
> last thread terminates. (Finishing main terminates the start-up
> thread, and thus the process if no other threads have been started.)
> Except
> that this doesn't apply to all threads -- you can declare a thread to
> be
> a daemon, in which case, the fact that it is still running doesn't
> prevent the process from terminating. (Presumably, Java has the same
> problem of a thread accessing inexistant ressources in the case of a
> daemon thread, or if the application calls exit.)
Intrestingly Win32 also does not terminate the process when the main thread
exits (at least on NT based platforms). If you write a program in C++
without using the runtime library (ignoring the non-standardness of this for
a moment) the application will continue to run after returning from main()
as long as there are some threads present.
It is the C++ library that made a choice to call ExitProcess from exit(). I
am not sure that this was a good decision but that's the way it is. The
library actually allows to override this behavior if required so it isn't a
big problem.
I don't think there is anything like daemon threads in Win32.
> Quite. In the applications I've written (mostly large scale servers),
> we've generally been master of most of the threads, and arranged to
> clean them up correctly. Although now that I think of it, I think
> that the data base (SyBase or Oracle) had some threads of its own, of
> which
> we weren't master. I'm not sure what ressources they might use,
> however. (We do ensure that all of the callbacks were deenregistered
> before returning from main.)
>
> In theory, Unix has a cancellation mechanism which should be able to
> be used for this. I'm not that familiar with it, however, since I've
> never had to use it, so I don't know how well it works in practice.
I don't think it can help but my knowledge of Unix is too limited to pass
any opinion here. In any case Windows lacks thread cancellation handlers
completely. This BTW presents problems for any library that needs to work on
someone else's threads. Basically if a library allocates a some per-thread
data on a caller's thread it has no good way to know when to clean it.
That's why many Windows libraries require the caller to call special
initialization/termination functions on each thread.
>> If the software is composed from components written in many
>> languages the C++ only standard won't help. This should be the
>> task for a platform ABI.
>
> And a standard interface to it at the C++ level? (Of course, if
> you're loading dynamic objects and running multi-threaded, you're
> already so
> far outside of just C++ that a little more probably won't hurt much.)
Well .NET and this new CLI C++ binding could contain something like this.
Would be interesting to see what, if anything, they decide to do.
>> Threading is also intermixed with dynamic loading. For example if
>> you unload all dynamic libraries then you need to shut down its
>> threads prior to that. I guess if someone wants to define what
>> happens on exit he should handle both issues simultaneously.
>>
>> This is the second time you've mentionned unloading dynamic objects.
>> Obviously, if you unload a dynamic object, you must make sure that no
>> one uses any of the ressources it contains after it has been unloaded.
>> But most of the time, at least in the applications I've seen, once a
>> dynamic object has been loaded, it stays loaded until program
>> termination. There are only a very few, and very controlled cases
>> where one would unload a dynamic object.
Well this case isn't frequent but it happens. Some technologies like COM
like to unload a DLL when it is no longer needed. Some interactive
applications may contain so many plugins that holding them all loaded may be
impractical. My point is that any comprehensive solution to threads in C++
_must_ take dynamic loading into account to be usefull.
--
Eugene
> Alexander Terekhov <tere...@web.de> wrote in message
> news:<4060305A...@web.de>...
> > ka...@gabi-soft.fr wrote:
> > [...]
> > > I think that we are basically in agreement. A thread should
> > > terminate by returning from its top level function, rather than be
> > > calling pthread_exit or its windows equivalent,
>
> > Windows equivalent and lack of "POSIX.C++" standard aside for a
> > moment, pthread_exit() (and thread cancellation) results in the
> > exception (stack unwinding) in C++.
>
> According to who?
C++ User's Guide, Sun(TM) ONE Studio 8, p 11-3
Note: Thread cancellation (pthread_cancel(3T)) results in the
destruction of automatic (local nonstatic) objects on the
stack. When a thread is cancelled, the execution of local
destructors is interleaved with the execution of cleanup routines
that the user has registered with pthread_cleanup_push(). The
local objects for functions called after a particular cleanup
routine is registered are destroyed before that routine is
executed.
And I seem to remember having seen similar thing for HP (and perhaps
IBM) but I'm currently unable to check.
Yours,
--
Jean-Marc
The POSIX standard "knows" about C++ and has said everything that is
possible to be said without mentioning C++ by name. Whereas the C++
standard not only doesn't mention threads, it doesn't even "know"
about them.
> The "logical" solution for an implementor would be to base himself on
> the existing -- pthread_exit() in C++ works with respect to a thread as
> does exit() with respect to a process. And exit() doesn't do any stack
> unwinding.
... whereas pthread_exit does. Cleanup handlers are invoked in stack
unwind order, and the POSIX standard explicitly acknowledges the
possibility that pthread_cleanup_* can be implemented as macros that
open/close a scope using '{' and '}' (the scope can be used to
construct a RAII object that does the cleanup).
"In addition, this mechanism is really only necessary due to the lack
of a real exception mechanism in the C language, which would be the
ideal solution."
How clearer can you be without saying "C++ exceptions"? The POSIX
folks have done everything they could. But no, the C++ community
insist on reinventing the wheel. Why should we use the existing, well
specified exception handling mechanism for thread cancelation when we
can come up with something new, "improved", and broken.
> > There's nothing wrong with respect to calling pthread_exit() on any
> > reasonable POSIX system which also supports threaded C++ in a
> > non-braindamaged manner, so to say.
>
> I'm just curious: how do you justify the fact that pthread_exit behaves
> differently with regard to a thread than exit with regard to a process?
Because process termination is not the same as thread cancelation?
pthread_exit() synchronously unwinds the local stack; exit() would
have to asynchronously unwind foreign stacks. pthread_exit() can be as
simple as "throw pthread_exit_exception();", but you can't implement
exit() with the existing exception mechanism.
> > > Windows equivalent and lack of "POSIX.C++" standard aside for a
> > > moment, pthread_exit() (and thread cancellation) results in the
> > > exception (stack unwinding) in C++.
> > According to who? The C++ standard doesn't say so, since it doesn't
> > know about threads. The Posix standard doesn't say so, since it
> > doesn't know about C++.
> The POSIX standard "knows" about C++ and has said everything that is
> possible to be said without mentioning C++ by name.
I don't think so. It doesn't mention destructors, for example, and
unless you specify when destructors are called, you haven't begun to say
anything useful about C++.
> Whereas the C++ standard not only doesn't mention threads, it doesn't
> even "know" about them.
In the same way, Posix doesn't know about C++.
> > The "logical" solution for an implementor would be to base himself
> > on the existing -- pthread_exit() in C++ works with respect to a
> > thread as does exit() with respect to a process. And exit() doesn't
> > do any stack unwinding.
> ... whereas pthread_exit does.
Posix doesn't say anything about it.
> Cleanup handlers are invoked in stack unwind order,
That's technically a separate stack, however.
> and the POSIX standard explicitly acknowledges the possibility that
> pthread_cleanup_* can be implemented as macros that open/close a scope
> using '{' and '}' (the scope can be used to construct a RAII object
> that does the cleanup).
The POSIX standard imposes constraints on their use which would allow
such an implementation. Saying that this means that there is stack
walkback is like saying that the constraints in std::string implies that
strings use COW. The goal is to allow a specific implementation
technique, without imposing it.
> "In addition, this mechanism is really only necessary due to the lack
> of a real exception mechanism in the C language, which would be the
> ideal solution."
> How clearer can you be without saying "C++ exceptions"? The POSIX
> folks have done everything they could.
OK. I didn't read the rationale before. The intention is clear.
> But no, the C++ community insist on reinventing the wheel. Why should
> we use the existing, well specified exception handling mechanism for
> thread cancelation when we can come up with something new, "improved",
> and broken.
I wasn't aware that the C++ community was doing anything for the
moment. At least not as a whole.
> > > There's nothing wrong with respect to calling pthread_exit() on
> > > any reasonable POSIX system which also supports threaded C++ in a
> > > non-braindamaged manner, so to say.
> > I'm just curious: how do you justify the fact that pthread_exit
> > behaves differently with regard to a thread than exit with regard to
> > a process?
> Because process termination is not the same as thread cancelation?
> pthread_exit() synchronously unwinds the local stack; exit() would
> have to asynchronously unwind foreign stacks. pthread_exit() can be
> as simple as "throw pthread_exit_exception();", but you can't
> implement exit() with the existing exception mechanism.
Sure you could. Basically, instead of defining the initialization
process as being the equivalent of:
exit( main( argc, argv ) ) ;
you define it as the equivalent of:
try
{
throw main( argc, argv ) ;
} catch ( int returnCode ) {
cleanUpAndReturn( returnCode ) ;
}
and exit(n) as:
void
exit( int n )
{
throw n ;
}
C++ doesn't do this, probably for historical reasons, but within the
context of modern C++, it might be a more reasonable approach.
My comparision of exit and pthread_exit, of course, was based on the use
of exit in a single threaded program. The semantics of exit were, of
course, originally defined for single threaded programs, and the
possibility of a stack walkback and cleanup functions was there.
--
James Kanze GABI Software mailto:ka...@gabi-soft.fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
> > Alexander Terekhov <tere...@web.de> wrote in message
> > news:<4060305A...@web.de>...
> > > ka...@gabi-soft.fr wrote:
> > > [...]
> > > > I think that we are basically in agreement. A thread should
> > > > terminate by returning from its top level function, rather than
> > > > be calling pthread_exit or its windows equivalent,
> > > Windows equivalent and lack of "POSIX.C++" standard aside for a
> > > moment, pthread_exit() (and thread cancellation) results in the
> > > exception (stack unwinding) in C++.
> > According to who?
> C++ User's Guide, Sun(TM) ONE Studio 8, p 11-3
> Note: Thread cancellation (pthread_cancel(3T)) results in the
> destruction of automatic (local nonstatic) objects on the
> stack. When a thread is cancelled, the execution of local
> destructors is interleaved with the execution of cleanup routines
> that the user has registered with pthread_cleanup_push(). The
> local objects for functions called after a particular cleanup
> routine is registered are destroyed before that routine is
> executed.
> And I seem to remember having seen similar thing for HP (and perhaps
> IBM) but I'm currently unable to check.
After posting, I tried it with SunCC (and with g++, but still under
Solaris), and was surprised to see that it did unwind the stack. I'm
still curious with regards to 1) the actual guarantees (since Posix
doesn't say anything about it), and 2) the motivation -- I would have
normally expected pthread_exit to be modeled on exit. (It's not really
a question about what is right or wrong, or really what is best -- I
like the fact that it unwinds the stack, and think that it would be
better if exit did as well. But given the semantics of exit, and the
lack of the slightest indication concerning C++ in Posix, it isn't
something that I would have expected.)
--
James Kanze GABI Software mailto:ka...@gabi-soft.fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
> But given the semantics of exit, and the lack of the slightest
> indication concerning C++ in Posix, it isn't something that I would
> have expected.)
There are some slight references to C++ in Posix, and most of the one
I've found are in relation to stack unwinding. For example in the
rational:
The interaction of this facility [Cleanup Handlers] and other
procedure-based or language-level exception facilities is
unspecified in this version of IEEE Std 1003.1-2001. However, it
is intended that it be possible for an implementation to define
the relationship between these cancelation cleanup handlers and
Ada, C++, or other language-level exception handling facilities.
and in System Interface:
A side effect of acting on a cancelation request while a thread is
blocked on a condition variable is to re-acquire the mutex before
calling any of the cancelation cleanup handlers. This is done in
order to ensure that the cancelation cleanup handler is executed
in the same state as the critical code that lies both before and
after the call to the condition wait function. This rule is also
required when interfacing to POSIX threads from languages, such as
Ada or C++, which may choose to map cancelation onto a language
exception;
Mapping thread_exit and thread_cancel to C++ exceptions is not a bad
choice (BTW, exit is nearly useless in C++ because it is such an half
backed solution: do some cleanup but not other and so thread_exit is
more usable in C++). The major problem is what to do in presence of
catch(...) especially when there is no rethrow and in presence of
attemps to reencapsulate the exception if the cancelling/exiting
exception is a descendend of std::exception.
Yours,
--
Jean-Marc
I can verify it for our implementation. There's no sensible way for the
runtime library to shut down user-created threads.
--
Pete Becker
Dinkumware, Ltd. (http://www.dinkumware.com)