Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Destructors and program termination

118 views
Skip to first unread message

Michi Henning

unread,
Aug 6, 2007, 1:36:38 AM8/6/07
to
I'm in the situation where I need to terminate a threaded program
from within a signal handler. I cannot call exit() because global
destructors may find data structures in an inconsistent state
and crash, or may deadlock on various mutexes. So, I'm calling _exit()
instead, which (at least for many implementations) prevents global
destructors from running.

The worrying thing is that the standard doesn't say anything about
exit() or _exit(), so I'm relying on implementation-dependent behavior.

Calling ::std::terminate() or ::abort() is not an option because
termination is expected and I want to return zero exit status to
the OS, but abort() and terminate() both return non-zero exit status
(and, for some environments, dump core or pop a dialog box about
abnormal program termination).

With threading being added to the upcoming standard, it seems important
that the standard say something about program termination. In
particular, as far as I can see, it is important to provide a portable
way to terminate a program that guarantees that no destructors will run,
and that allows a program to control exit status. Without such a
feature, it becomes basically impossible to terminate a threaded program
prematurely without running the risk of undefined behavior, due to
destructors doing unexpected things.

Note that the problem also arises for non-threaded programs: in general,
it is not safe to call exit() from a signal handler because that might
cause undefined behavior (because data structure may be in an
inconsistent state, causing destructors to fall over). _exit()
usually works, but does not exist as far as the standard is concerned.

All alternatives that I can see for terminating safely in response
to a signal are cumbersome. I could, for example, set a flag in
the signal handler, but then all other threads in the program would
have to periodically test for that flag (and some threads might be
stuck in blocking system calls).

Also, the problem is not limited to asynchronous signals. Simply
terminating a threaded program, for example, in response to user input
(such as pressing an "Exit" button) can require a lot of work: somehow,
I have to signal all threads and get them to terminate in order to
make the program go away.

So, it seems we need something in the standard for this?

Until that happens (if it happens), are there any other suggestions
for how I can make my program disappear without risking undefined
behavior?

Thanks,

Michi.

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Bjørn Roald

unread,
Aug 6, 2007, 4:53:26 AM8/6/07
to
Michi Henning wrote:
> I'm in the situation where I need to terminate a threaded program
> from within a signal handler. I cannot call exit() because global
> destructors may find data structures in an inconsistent state
> and crash, or may deadlock on various mutexes. So, I'm calling _exit()
> instead, which (at least for many implementations) prevents global
> destructors from running.
>
> The worrying thing is that the standard doesn't say anything about
> exit() or _exit(), so I'm relying on implementation-dependent behavior.
>
> Calling ::std::terminate() or ::abort() is not an option because
> termination is expected and I want to return zero exit status to
> the OS, but abort() and terminate() both return non-zero exit status
> (and, for some environments, dump core or pop a dialog box about
> abnormal program termination).
>
> With threading being added to the upcoming standard, it seems important
> that the standard say something about program termination. In
> particular, as far as I can see, it is important to provide a portable
> way to terminate a program that guarantees that no destructors will run,
> and that allows a program to control exit status. Without such a
> feature, it becomes basically impossible to terminate a threaded program
> prematurely without running the risk of undefined behavior, due to
> destructors doing unexpected things.

I see your point and I think it would help, but how does terminating
without destructors really avoid undefined behavior. Is it standarized
somewhere how operating environments shall reclaim resources after
processes/programs end? I believe not. A key point here, I guess, is
whether you have control of which objects are destroyed without
destruction. If you did, you may say the behavior is defined, in a
limited sense, at least as far as C++ goes.

> Note that the problem also arises for non-threaded programs: in general,
> it is not safe to call exit() from a signal handler because that might
> cause undefined behavior (because data structure may be in an
> inconsistent state, causing destructors to fall over). _exit()
> usually works, but does not exist as far as the standard is concerned.
>
> All alternatives that I can see for terminating safely in response
> to a signal are cumbersome. I could, for example, set a flag in
> the signal handler, but then all other threads in the program would
> have to periodically test for that flag (and some threads might be
> stuck in blocking system calls).
>
> Also, the problem is not limited to asynchronous signals. Simply
> terminating a threaded program, for example, in response to user input
> (such as pressing an "Exit" button) can require a lot of work: somehow,
> I have to signal all threads and get them to terminate in order to
> make the program go away.
>
> So, it seems we need something in the standard for this?

Agree, the fact that this stuff is difficult to get right make it prime
candidate for standardization.

> Until that happens (if it happens), are there any other suggestions
> for how I can make my program disappear without risking undefined
> behavior?

If destructors of globals was all you worried about, then you should
consider avoiding using global lifetime objects with none-trivial
destruction. However I suspect threading make it a lot harder than
that. So I would look for hints to solutions in libraries that make
object and thread lifetime management a libriary feature. Loki
Singelton has a longlivity policy. ACE got some object and thread
management stuff.

--
Bjørn

Greg Herlihy

unread,
Aug 6, 2007, 6:19:45 PM8/6/07
to
On 8/5/07 10:36 PM, in article 6fvti.17054$tp3....@nasal.pacific.net.au,
"Michi Henning" <mi...@zeroc.com> wrote:

> I'm in the situation where I need to terminate a threaded program
> from within a signal handler. I cannot call exit() because global
> destructors may find data structures in an inconsistent state
> and crash, or may deadlock on various mutexes. So, I'm calling _exit()
> instead, which (at least for many implementations) prevents global
> destructors from running.

Calling _exit() (which presumably should be "_Exit()") - does not "prevent"
C++ global objects from being destroyed. The destruction of a C++ program's
global objects is not inevitable. Instead a C++ program is responsible for
destroying its own global objects - and can do so in one of two ways: the
program returns from main() or it calls exit(). So a C++ program that fails
to exit main() and neglects to call exit() before it terminates - will not
have destroyed its global objects by the time it ended.

> The worrying thing is that the standard doesn't say anything about
> exit() or _exit(), so I'm relying on implementation-dependent behavior.

Not so. The C++ Standard specifies that calling exit() destroys global
objects[3.6.3/1] And _Exit() is part of the C99 Standard (and will
presumably be incorporated into the next C++ Standard by reference).

I don't see any implementation-defined behavior here. Calling _Exit() is no
more likely to destroy a C++ program's global objects than calling printf()
- or calling any other function that is not exit().



> With threading being added to the upcoming standard, it seems important
> that the standard say something about program termination. In
> particular, as far as I can see, it is important to provide a portable
> way to terminate a program that guarantees that no destructors will run,
> and that allows a program to control exit status. Without such a
> feature, it becomes basically impossible to terminate a threaded program
> prematurely without running the risk of undefined behavior, due to
> destructors doing unexpected things.

It's easy to prevent global objects from being destroyed - don't have the
program return from main() and don't have the program call exit() before it
terminates.



> Note that the problem also arises for non-threaded programs: in general,
> it is not safe to call exit() from a signal handler because that might
> cause undefined behavior (because data structure may be in an
> inconsistent state, causing destructors to fall over). _exit()
> usually works, but does not exist as far as the standard is concerned.

The Standard specifies the one routine that does destroy global objects. We
are expected to deduce from that information - the list of routines that do
not destroy a C++ program's global objects.

> All alternatives that I can see for terminating safely in response
> to a signal are cumbersome. I could, for example, set a flag in
> the signal handler, but then all other threads in the program would
> have to periodically test for that flag (and some threads might be
> stuck in blocking system calls).

Closing the object that the thread is waiting upon (such a socket) is
usually enough to unblock a waiting thread. And certainly the greater the
number of threads in a program, the harder it becomes to shut the program
down in an orderly fashion. So some good advice would be: not to create more
threads than are needed - or to consider a multi-process implementation
instead.



> Also, the problem is not limited to asynchronous signals. Simply
> terminating a threaded program, for example, in response to user input
> (such as pressing an "Exit" button) can require a lot of work: somehow,
> I have to signal all threads and get them to terminate in order to
> make the program go away.
>
> So, it seems we need something in the standard for this?

I am not so sure. Conducting an orderly shutdown seems to be a program
design issue - not something that the C++ language could directly address.

> Until that happens (if it happens), are there any other suggestions
> for how I can make my program disappear without risking undefined
> behavior?

Once the C++ program calls _Exit() - its behavior becomes nonexistent - not
undefined.

Greg

Michi Henning

unread,
Aug 7, 2007, 4:19:45 AM8/7/07
to
Bjørn Roald wrote:

> I see your point and I think it would help, but how does terminating
> without destructors really avoid undefined behavior. Is it standarized
> somewhere how operating environments shall reclaim resources after
> processes/programs end? I believe not. A key point here, I guess, is
> whether you have control of which objects are destroyed without
> destruction. If you did, you may say the behavior is defined, in a
> limited sense, at least as far as C++ goes.

The issue is simply that destructors may do things that are not safe
if they are called while other threads are still executing, or if they
are called asynchronously, such as from a signal handler. For example,
a destructor may attempt to lock a mutex--if the signal arrives while
another thread holds that mutex, and the signal handler calls exit(),
the destructor will deadlock.

For single-threaded programs, a similar problem can arise. For example,
a destructor might traverse a linked list but, at the time the signal
arrived, the list may be in an inconsistent state because it was in
the process of being modified.

So, I think what's needed is a way to terminate a program that;

- allows me to control the exit status

- guarantees that destructors will *not* run

> If destructors of globals was all you worried about, then you should
> consider avoiding using global lifetime objects with none-trivial
> destruction. However I suspect threading make it a lot harder than
> that. So I would look for hints to solutions in libraries that make
> object and thread lifetime management a libriary feature. Loki
> Singelton has a longlivity policy. ACE got some object and thread
> management stuff.

Doing this often is not an option because the global objects may live
inside a library that I'm linking against and over whose actions I
have no control.

Cheers,

Michi.


--

Michi Henning

unread,
Aug 7, 2007, 4:21:28 AM8/7/07
to
Greg Herlihy wrote:

> Calling _exit() (which presumably should be "_Exit()") - does not "prevent"
> C++ global objects from being destroyed. The destruction of a C++ program's
> global objects is not inevitable. Instead a C++ program is responsible for
> destroying its own global objects - and can do so in one of two ways: the
> program returns from main() or it calls exit(). So a C++ program that fails
> to exit main() and neglects to call exit() before it terminates - will not
> have destroyed its global objects by the time it ended.

I don't believe that follows from what is written in the standard.

As far as I can see, when I call exit(), the spec guarantees that:

- Destructors for objects with automatic storage duration
will not be called.

- Destructors for objects with with static storage duration
will be called, in reverse order of construction.

>> The worrying thing is that the standard doesn't say anything about
>> exit() or _exit(), so I'm relying on implementation-dependent behavior.
>
> Not so. The C++ Standard specifies that calling exit() destroys global
> objects[3.6.3/1] And _Exit() is part of the C99 Standard (and will
> presumably be incorporated into the next C++ Standard by reference).

Right, the C++ standard says what exit() does, but it doesn't say what
_exit() or _Exit() do. And the C standard certainly doesn't say
anything about C++ destructors.

> I don't see any implementation-defined behavior here. Calling _Exit() is no
> more likely to destroy a C++ program's global objects than calling printf()
> - or calling any other function that is not exit().

_exit() and _Exit() are specified not to call any functions registered
atexit() or on_exit(). However, that's not useful for C++ because the
C++ spec doesn't say by what means the run time takes care of calling
destructors of objects with static storage duration. A compliant
implementation could use a mechanism other than atexit() or on_exit()
to invoke static destructors.

In other words, the C++ spec does not say anything all about the
behavior of _exit() or _Exit(). Therefore, I cannot make any assumptions
about whether or not calling either function will cause destructors
of static objects to run or not.

>
>> With threading being added to the upcoming standard, it seems important
>> that the standard say something about program termination. In
>> particular, as far as I can see, it is important to provide a portable
>> way to terminate a program that guarantees that no destructors will run,
>> and that allows a program to control exit status. Without such a
>> feature, it becomes basically impossible to terminate a threaded program
>> prematurely without running the risk of undefined behavior, due to
>> destructors doing unexpected things.
>
> It's easy to prevent global objects from being destroyed - don't have the
> program return from main() and don't have the program call exit() before it
> terminates.

Neither the C++ nor the C standard provide any such guarantee.
The spec says that calling exit() will run static destructors, but
that does not guarantee that they will *not* run if I call _exit().

> The Standard specifies the one routine that does destroy global objects. We
> are expected to deduce from that information - the list of routines that do
> not destroy a C++ program's global objects.

I disagree. The standard says that:

- *IF* I call exit(), *THEN* global destructors will run.

That statements says *nothing* about what happens if I terminate
the program by calling _exit().

I agree that, at least for most implementations, _exit() indeed
suppresses static destructors. But the point is that the spec
doesn't promise that this is what must happen. As far as I can see
an implementation that runs static destructors when I call _exit()
is perfectly compliant because there are no words in the spec
to say otherwise.

> Closing the object that the thread is waiting upon (such a socket) is
> usually enough to unblock a waiting thread.

The object that the thread is waiting on may not be immediately obvious.
I may have hundreds of such objects, only on some of which a thread
is waiting on. What am I supposed to do? Globally keep track of all
these objects so I can close them just in case there might be a thread
waiting on one of them?

Similarly, a thread may be blocked on a mutex or waiting on a condvar.

In practice, it simply isn't feasible to arrange for all threads to
terminate cleanly. This is particularly true if the threads
are created by a library and, officially, the program doesn't know
that these even threads exist; even if the program does know about
these threads, there is no portable way to get at their thread
handles or at the synchronization primitives those threads might
have locked.

> And certainly the greater the
> number of threads in a program, the harder it becomes to shut the program
> down in an orderly fashion. So some good advice would be: not to create more
> threads than are needed - or to consider a multi-process implementation
> instead.

As I said, I often have no control over that at all, because the threads
may be created by a library over which I have no control.

> I am not so sure. Conducting an orderly shutdown seems to be a program
> design issue - not something that the C++ language could directly address.

My point is that, without at least minimal assistance form the standard
(such as a promise not to call destructors when I call some exit
function), achieving orderly shutdown is pragmatically impossible for
some programs.

>> Until that happens (if it happens), are there any other suggestions
>> for how I can make my program disappear without risking undefined
>> behavior?
>
> Once the C++ program calls _Exit() - its behavior becomes nonexistent - not
> undefined.

I cannot find words in either the C++ or the C standard to confirm that.

Cheers,

Michi.

Carl Barron

unread,
Aug 7, 2007, 4:22:31 AM8/7/07
to
In article <C2DCD6DE.D6EF%gre...@pacbell.net>, Greg Herlihy
<gre...@pacbell.net> wrote:

>
> Not so. The C++ Standard specifies that calling exit() destroys global
> objects[3.6.3/1] And _Exit() is part of the C99 Standard (and will
> presumably be incorporated into the next C++ Standard by reference).

FWIW calling exit() will not destruct any non-global objects. I
prefer to use an exception caught in main() that will unwind the stack
as well before executing a call of exit(). even a catch(...) block in
main will suffice the catch block calls exit or returns as the effect
of exit is to go to where ever main returns to.

HumbleWorker

unread,
Aug 7, 2007, 10:42:19 AM8/7/07
to
> All alternatives that I can see for terminating safely in response
> to a signal are cumbersome. I could, for example, set a flag in
> the signal handler, but then all other threads in the program would
> have to periodically test for that flag (and some threads might be
> stuck in blocking system calls).
>
Why not use a global flag which is set by the signal at the time
premature termination is desired ? The same flag should be tested in
each of the destructors before executing the code contained in the
destructors.
The flag could be a class member of the objects being destroyed, just
like we use a flag in constructors for indicating ownership of an
object.

Michi Henning

unread,
Aug 8, 2007, 12:34:54 AM8/8/07
to
HumbleWorker wrote:

> Why not use a global flag which is set by the signal at the time
> premature termination is desired ? The same flag should be tested in
> each of the destructors before executing the code contained in the
> destructors.
> The flag could be a class member of the objects being destroyed, just
> like we use a flag in constructors for indicating ownership of an
> object.

This would work, but only some of the time. In particular, it doesn't
work for destructors of objects that are part of a library I'm linking
against and for which I do not have source code.

Also, I see a number of serious drawbacks of this approach:

- It is intrusive to each class that has a static instance.

- Every time a new static instance is added to the program, I have
to check whether the corresponding class's destructor conforms
to this scheme and, if not, modify the destructor of the class.

- The approach creates "action at a distance": setting a global
flag in one place modifies the behavior of an unknown number
of destructors in completely unrelated places.

So, I appreciate the suggestion but, realistically, I think doing
this would lead to rather brittle and unmaintainable code.

Cheers,

Michi.

Bjørn Roald

unread,
Aug 8, 2007, 4:13:08 AM8/8/07
to
Michi Henning wrote:
> Bjørn Roald wrote:
>
>> I see your point and I think it would help, but how does terminating
>> without destructors really avoid undefined behavior. Is it standarized
>> somewhere how operating environments shall reclaim resources after
>> processes/programs end? I believe not. A key point here, I guess, is
>> whether you have control of which objects are destroyed without
>> destruction. If you did, you may say the behavior is defined, in a
>> limited sense, at least as far as C++ goes.
>
> The issue is simply that destructors may do things that are not safe
> if they are called while other threads are still executing, or if they
> are called asynchronously, such as from a signal handler. For example,
> a destructor may attempt to lock a mutex--if the signal arrives while
> another thread holds that mutex, and the signal handler calls exit(),
> the destructor will deadlock.
>
> For single-threaded programs, a similar problem can arise. For example,
> a destructor might traverse a linked list but, at the time the signal
> arrived, the list may be in an inconsistent state because it was in
> the process of being modified.
>
> So, I think what's needed is a way to terminate a program that;
>
> - allows me to control the exit status
>
> - guarantees that destructors will *not* run

I did get this from your former post. I was just questioning your
rationale for the method as skipping destructors as well may have
undesired effect even at shutdown.

All the relevant effects of exit(), _exit() and _Exit() are not defined
by the C and C++ standards, and they may never be. You may have too
look elsewhere, POSIX, OS docs etc. as relevant for your targets. As
example the man page for exit, attribure and standard for Solaris would
give me some comfort of using _Exit() or other means of your method on
that platform.

http://docs.sun.com/app/docs/doc/816-5167/6mbb2jaft?a=view
http://docs.sun.com/app/docs/doc/816-0220/6m6nkorrh?l=en&a=view

>> If destructors of globals was all you worried about, then you should
>> consider avoiding using global lifetime objects with none-trivial
>> destruction. However I suspect threading make it a lot harder than
>> that. So I would look for hints to solutions in libraries that make
>> object and thread lifetime management a libriary feature. Loki
>> Singelton has a longlivity policy. ACE got some object and thread
>> management stuff.
>
> Doing this often is not an option because the global objects may live
> inside a library that I'm linking against and over whose actions I
> have no control.

For those of us that write or maintain libraries, such globals should be
hunted with vigor. The same apply to threads, event loops, etc. hidden
inside libraries. In my book this is reasons to look for other
libraries. There is nothing wrong in libraries helping setting up such
constructs, but they should give the user means to control them.

My reference to the above libraries was not mainly to suggest you should
use them, I have no reason to know whether that is feasible, but I
wanted too suggest you take a look around in such libraries for hints as
how to shut down objects, threads, processes, etc. in a controlled
portable fashion in C++. I do not know if you will find gold but it
seems worth taking a look.

--
Bjørn

Maciej Sobczak

unread,
Aug 8, 2007, 9:01:56 AM8/8/07
to
On 8 Sie, 06:34, Michi Henning <mi...@zeroc.com> wrote:

> > Why not use a global flag which is set by the signal at the time
> > premature termination is desired ? The same flag should be tested in
> > each of the destructors before executing the code contained in the
> > destructors.

> This would work, but only some of the time. In particular, it doesn't


> work for destructors of objects that are part of a library I'm linking
> against and for which I do not have source code.

It might not be technically helping, but the problem of not having a
source code is not a language issue, but the business model issue. It
is entirely the consequence of your relation with the provider of the
component you are using.

> Also, I see a number of serious drawbacks of this approach:
>
> - It is intrusive to each class that has a static instance.

[...]

Not necessarily:

struct MyWrapperForAllGlobals
{
MyWrapperForAllGlobals()
{
px = new X;
py = new Y;
pz = new Z;
// ...
}

~MyWrapperForAllGlobals()
{
if (itIsOKToDestroyGlobals)
{
delete px;
delete py;
delete pz;
// ...
}
}

X *px;
Y *py;
Z *pz;
// ...
};

MyWrapperForAllGlobals mwfag;

X &x = *mwfag.px;
Y &y = *mwfag.py;
Z &z = *mwfag.pz;
// ...

Now x, y and z are global names that can be used as if they were
global objects, except that you can control whether it is safe to
destroy them - and there is only one place where this is done. Non-
intrusively.

--
Maciej Sobczak
http://www.msobczak.com/

Lance Diduck

unread,
Aug 8, 2007, 10:48:32 PM8/8/07
to
On Aug 6, 1:36 am, Michi Henning <mi...@zeroc.com> wrote:

> All alternatives that I can see for terminating safely in response
> to a signal are cumbersome. I could, for example, set a flag in
> the signal handler, but then all other threads in the program would
> have to periodically test for that flag (and some threads might be
> stuck in blocking system calls).

I assume you are using pthreads, and, you join all the threads before
leaving main().
The preferred way to do this is to trap the signal, and instead of
calling exit() or whatever, call pthread_cancel on each thread. Since
the vast majority of system calls are also cancellation points, if
your thread is blocked on some IO, like read() or select() for
instance, it will stop, and then execute anything you put in the
pthread_cleanup_push() handlers. Other blocking things like condvar
waits, sleeps, and such are also cancellation points. Locks are not,
but hopefully your cleanup routines are freeing those.
When all the threads have terminated and done their respective
cleanup, then the join clause will resume in your main, and you can
then return any value you wish.

I have always found that programs that somehow has destructors that
can fail need to have their design reevaluated.
Lance

ap...@student.open.ac.uk

unread,
Aug 9, 2007, 1:39:48 PM8/9/07
to
Lance Diduck wrote:
> I have always found that programs that somehow has destructors that
> can fail need to have their design reevaluated.
> Lance

<aol>me too</aol>. I must admit, I was concerned when I thought about
the work that must be going on, basically just to free resources. It
should be simple and must not fail (so if a dtor calls routines that
can throw it should trap the exception and silently absorb it to
prevent it propagating outside the dtor).

I have recently coded something that uses cond vars, mutexes, threads
etc where I had to provide an orderly shutdown in the event that a
third-party library threw a wobblie. I made it so that the thread that
picks events up from library does so via a mechanism that allows me to
send messages as well as the API. The API rcvs its events by doing
select for a bunch of sockets so I create a pipe and add the file
descriptor to the collection of sockets being listened to. The thread
that does the listening I call the listening thread. The thread that
creates the listening thread I call the parent thread. This allows the
parent thread to send a msg to the listening thread to tell it to
stop. The parent thread owns a list that is protected by a mutex that
the listening thread can also access. This reminds me of the situation
described by the OP. So the parent threads waits on a cond var that is
signalled by the listening thread when the listening thread is about
to terminate. This means the parent thread can destroy the list
without having to worry about the listening thread trying to take a
lock on it.

-Andrew Marlow

Michi Henning

unread,
Aug 14, 2007, 12:53:27 AM8/14/07
to
Carl Barron wrote:

> FWIW calling exit() will not destruct any non-global objects. I
> prefer to use an exception caught in main() that will unwind the stack
> as well before executing a call of exit(). even a catch(...) block in
> main will suffice the catch block calls exit or returns as the effect
> of exit is to go to where ever main returns to.

I don't see how that would help with respect to threads or signal
handlers. If the main thread calls exit without joining with all
existing threads, I can still suffer undefined behavior.

Cheers,

Michi.

Michi Henning

unread,
Aug 14, 2007, 12:55:34 AM8/14/07
to
ap...@student.open.ac.uk wrote:

> <aol>me too</aol>. I must admit, I was concerned when I thought about
> the work that must be going on, basically just to free resources. It
> should be simple and must not fail (so if a dtor calls routines that
> can throw it should trap the exception and silently absorb it to
> prevent it propagating outside the dtor).

The problem is not exceptions, the problem is, for example, deadlock
on mutexes that are locked by other threads (or maybe the same thread,
in case of a signal).

> I have recently coded something that uses cond vars, mutexes, threads
> etc where I had to provide an orderly shutdown in the event that a
> third-party library threw a wobblie. I made it so that the thread that
> picks events up from library does so via a mechanism that allows me to
> send messages as well as the API.

> // ...

In some scenarios (such as when I'm linking against a library that
doesn't provide all the necessary machinery for that kind of
shutdown), this is simply not an option.

But even when it *is* an option, I shouldn't have to jump through
all these hoops just make a process go away.

Cheers,

Michi.

Michi Henning

unread,
Aug 14, 2007, 12:55:15 AM8/14/07
to
Lance Diduck wrote:
> On Aug 6, 1:36 am, Michi Henning <mi...@zeroc.com> wrote:
>
>> All alternatives that I can see for terminating safely in response
>> to a signal are cumbersome. I could, for example, set a flag in
>> the signal handler, but then all other threads in the program would
>> have to periodically test for that flag (and some threads might be
>> stuck in blocking system calls).
> I assume you are using pthreads, and, you join all the threads before
> leaving main().

Not necessarily. It's pthreads for Linux platforms, Windows threads for
Windows, and even custom threads for other, more exotic platforms.

> The preferred way to do this is to trap the signal, and instead of
> calling exit() or whatever, call pthread_cancel on each thread.

Unfortunately, not all threading libraries provide cancellation.

> Since
> the vast majority of system calls are also cancellation points, if
> your thread is blocked on some IO, like read() or select() for
> instance, it will stop, and then execute anything you put in the
> pthread_cleanup_push() handlers. Other blocking things like condvar
> waits, sleeps, and such are also cancellation points. Locks are not,
> but hopefully your cleanup routines are freeing those.
> When all the threads have terminated and done their respective
> cleanup, then the join clause will resume in your main, and you can
> then return any value you wish.

Theoretically, I could do all this. But should it really be necessary
to have to jump through all those hoops just to make a process terminate
without dumping core? Why can't the standard simply provide me with a
function call that terminates the process immediately and without
further ado? That way, I wouldn't have to do any of these things and
could simply call _exit_immediately() (or whatever it would be called).

> I have always found that programs that somehow has destructors that
> can fail need to have their design reevaluated.

I believe that to be a gross generalization. There are legitimate
reasons for such destructors, and there are scenarios where the
use of such destructors simply cannot be avoided. If a thread
calls exit() at the wrong moment, the destructor may hang or do
other undefined things.

In summary, the C++ language provides global objects with destructors.
In the presence of threads, and in the presence of asynchronous signals,
these destructors can do undesirable things, with no pragmatically
acceptable way for the program to stop these destructors from running.

It seems to follow that the standard should provide a way to terminate
a process in a way that guarantees that global destructors won't run,
and in a way that allows the calling thread to control the exit status
of the program.

Cheers,

Michi.

{ clc++m banner removed -- please remove it yourself. -mod }

Michi Henning

unread,
Aug 14, 2007, 12:54:06 AM8/14/07
to
Maciej Sobczak wrote:

> Now x, y and z are global names that can be used as if they were
> global objects, except that you can control whether it is safe to
> destroy them - and there is only one place where this is done. Non-
> intrusively.

That's an interesting technique, thanks for that! But it doesn't solve
the problem if the objects are buried inside a library, I'm afraid.

Cheers,

Michi.

Michi Henning

unread,
Aug 14, 2007, 12:53:58 AM8/14/07
to
Bjørn Roald wrote:

> Michi Henning wrote:
>>
>> Doing this often is not an option because the global objects may live
>> inside a library that I'm linking against and over whose actions I
>> have no control.
>
> For those of us that write or maintain libraries, such globals should be
> hunted with vigor. The same apply to threads, event loops, etc. hidden
> inside libraries.

I avoid globals too and, in general, this is good advice. However, I
don't believe it is realistic: often, I simply have no choice about
what the library does that I have to link with.

In my particular case, the problem is caused in the Ice library
(www.zeroc.com), which is extensively threaded. (And providing
middleware that is not threaded is simply not a realistic options.)

In general, there are good and legitimate reasons for libraries to
create global objects (just think of cin, cout, and cerr), and for
libraries to create threads. These reasons won't go away and, without
some help from the spec, I can't see how a program linking against
such a library can terminate safely.

> In my book this is reasons to look for other
> libraries. There is nothing wrong in libraries helping setting up such
> constructs, but they should give the user means to control them.

As I said above, for some libraries, that is simply not a realistic
expectation.

> My reference to the above libraries was not mainly to suggest you should
> use them, I have no reason to know whether that is feasible, but I
> wanted too suggest you take a look around in such libraries for hints as
> how to shut down objects, threads, processes, etc. in a controlled
> portable fashion in C++. I do not know if you will find gold but it
> seems worth taking a look.

I am the author of that library :-) And, believe me, there is no way
for the application to shut down that library from a signal handling
context that isn't unspeakably messy, other than calling _exit().
And _exit() works fine in practice, except that the standard does not
guarantee me that it will...

Cheers,

Michi.


--

Maciej Sobczak

unread,
Aug 14, 2007, 2:49:49 PM8/14/07
to
On 14 Sie, 06:54, Michi Henning <mi...@zeroc.com> wrote:

> > Now x, y and z are global names that can be used as if they were
> > global objects, except that you can control whether it is safe to
> > destroy them - and there is only one place where this is done. Non-
> > intrusively.
>
> That's an interesting technique, thanks for that!

Note that the same trick (renaming with global reference) can be also
used to handle exceptions that are thrown from constructors of global
objects.

> But it doesn't solve
> the problem if the objects are buried inside a library, I'm afraid.

That's right. Not only global objects inside a library, but also
static objects buried in functions all over the project. I have no
idea how to tackle this, if not by going into extremes and extracting
the sensitive pieces into separate processes and turning everything
into a regular client-server system.
No silver bullets.

--
Maciej Sobczak
http://www.msobczak.com/

Francis Glassborow

unread,
Aug 14, 2007, 2:54:26 PM8/14/07
to
Michi Henning wrote:
> Bjørn Roald wrote:
>> Michi Henning wrote:
>>>
>>> Doing this often is not an option because the global objects may live
>>> inside a library that I'm linking against and over whose actions I
>>> have no control.
>>
>> For those of us that write or maintain libraries, such globals should be
>> hunted with vigor. The same apply to threads, event loops, etc. hidden
>> inside libraries.
>
> I avoid globals too and, in general, this is good advice. However, I
> don't believe it is realistic: often, I simply have no choice about
> what the library does that I have to link with.
>
> In my particular case, the problem is caused in the Ice library
> (www.zeroc.com), which is extensively threaded. (And providing
> middleware that is not threaded is simply not a realistic options.)
>


Well as the current version of Standard C++ has nothing to say on the
subject of threading, there will be no standard solution to problems
resulting from using a library that uses multithreading.

--
Note that robinton.demon.co.uk addresses are no longer valid.

Francis Glassborow

unread,
Aug 14, 2007, 2:54:38 PM8/14/07
to

Of course providing such may seem very easy, but believe me it is taking
a group of world class language experts a great deal of time to specify
exactly how that should be supported in the next version of C++.
Threading, particularly on multi-core machines, is very far from trivial.

>
>> I have always found that programs that somehow has destructors that
>> can fail need to have their design reevaluated.
>
> I believe that to be a gross generalization.

No it isn't. Much of C++ is designed on the implicit assumption that
dtors do not fail. If you find such dtors necessary then solving the
resulting problems is entirely your problem :-)

There are legitimate
> reasons for such destructors, and there are scenarios where the
> use of such destructors simply cannot be avoided. If a thread
> calls exit() at the wrong moment, the destructor may hang or do
> other undefined things.
>
>

--
Note that robinton.demon.co.uk addresses are no longer valid.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Hyman Rosen

unread,
Aug 14, 2007, 2:56:47 PM8/14/07
to
Michi Henning wrote:
> without some help from the spec, I can't see how a program
> linking against such a library can terminate safely.

Well, since the standard does not cover threads, you shouldn't
be able to see how a program linking with such a library can run
safely at all, much less terminate safely.

The answer is that in C++, threading behavior is implementation-
defined. You must look to the documentation for each platform on
which the program is to run on how to shut down in the way you
want. If it happens that it's always the same, calling _exit(),
then lucky you. Otherwise, you need to build the program properly
for each platform.

Bjørn Roald

unread,
Aug 14, 2007, 11:17:34 PM8/14/07
to
Michi Henning wrote:
> Bjørn Roald wrote:
>> Michi Henning wrote:
>>>
>>> Doing this often is not an option because the global objects may live
>>> inside a library that I'm linking against and over whose actions I
>>> have no control.
>>
>> For those of us that write or maintain libraries, such globals should be
>> hunted with vigor. The same apply to threads, event loops, etc. hidden
>> inside libraries.
>
> I avoid globals too and, in general, this is good advice. However, I
> don't believe it is realistic: often, I simply have no choice about
> what the library does that I have to link with.

In that case you are stuck. A relevant question to ask yourselves may
be why you _have_ too link to this library.

> In my particular case, the problem is caused in the Ice library
> (www.zeroc.com), which is extensively threaded. (And providing
> middleware that is not threaded is simply not a realistic options.)

That Ice or other middleware libs use threads are perfectly Ok. But
they should not manage the threads in a way hidden to the application.
Further, the control of the threads should not be beyond the reach of
the application code. If I was using Ice, and I have been considering
it as it seems to be very nice, I would prefer to create, own, and
manage all the threads myself. In the threads I would like Ice to use,
I would like to start, stop, suspend, and resume an event handling
mechanism provided by Ice. The threading and concurrency model of my
application would then be completely in my control. At a minimum, Ice
should provide me with the option of having such control of the
threading in my application.

By the way, have you studied asynchron I/O methods in Boost::Asio as an
alternative or addition to threading?

>
> In general, there are good and legitimate reasons for libraries to
> create global objects (just think of cin, cout, and cerr), and for
> libraries to create threads. These reasons won't go away and, without
> some help from the spec, I can't see how a program linking against
> such a library can terminate safely.

If I am not mistaken, cout etc. are references to the global objects.
I.e. I do not have to use them, I can "redirect" to any compatible
stream/streambuff object in my application. Hence, I have control.

http://www.gamedev.net/community/forums/topic.asp?topic_id=227598

>> In my book this is reasons to look for other
>> libraries. There is nothing wrong in libraries helping setting up such
>> constructs, but they should give the user means to control them.
>
> As I said above, for some libraries, that is simply not a realistic
> expectation.

I think it is, it just take a little careful thinking.

>> My reference to the above libraries was not mainly to suggest you should
>> use them, I have no reason to know whether that is feasible, but I
>> wanted too suggest you take a look around in such libraries for hints as
>> how to shut down objects, threads, processes, etc. in a controlled
>> portable fashion in C++. I do not know if you will find gold but it
>> seems worth taking a look.
>
> I am the author of that library :-) And, believe me, there is no way
> for the application to shut down that library from a signal handling
> context that isn't unspeakably messy, other than calling _exit().
> And _exit() works fine in practice, except that the standard does not
> guarantee me that it will...

At this point I am slightly confused. I do not know if it matters for
the discussion, but is your concern that there not possible to provide a
library as Ice with a clean way for applications using it to shut down?
As I pointed out before, using _Exit() or _exit() may work Ok on some
platforms and for some applications, but I do not think it is a good
clean shut-down that I ever would recommend in general. I think it is
possible for Ice to do better. One often simple approach is to make the
core issues a problem for the application, not something you need to
solve in the library. I think some problems become very hard to do
right if you insist on solving them hidden deep in the library.

--
Bjørn

Michi Henning

unread,
Aug 16, 2007, 6:29:12 AM8/16/07
to
Francis Glassborow wrote:
> Michi Henning wrote:

>> In my particular case, the problem is caused in the Ice library
>> (www.zeroc.com), which is extensively threaded. (And providing
>> middleware that is not threaded is simply not a realistic options.)
>>
>
>
> Well as the current version of Standard C++ has nothing to say on the
> subject of threading, there will be no standard solution to problems
> resulting from using a library that uses multithreading.

Right. However, the next version will talk about threading, so it
should address this issue. And, as I pointed out earlier, shutting down
is also an issue for single-threaded programs, such as when a single
handler wants to terminate a program. So, I see this also as a problem
with the current standard.

Cheers,

Michi.

--

Michi Henning

unread,
Aug 16, 2007, 6:30:00 AM8/16/07
to
Francis Glassborow wrote:
> Michi Henning wrote:
>>
>> Theoretically, I could do all this. But should it really be necessary
>> to have to jump through all those hoops just to make a process terminate
>> without dumping core? Why can't the standard simply provide me with a
>> function call that terminates the process immediately and without
>> further ado? That way, I wouldn't have to do any of these things and
>> could simply call _exit_immediately() (or whatever it would be called).
>
> Of course providing such may seem very easy, but believe me it is taking
> a group of world class language experts a great deal of time to specify
> exactly how that should be supported in the next version of C++.
> Threading, particularly on multi-core machines, is very far from trivial.

I know that it's not trivial :-) But, just because it may be difficult
to specify _exit_immediately() doesn't mean that it shouldn't be
specified. The only thing that should matter is whether it is needed.
(Personally, I believe it *is* needed because, for some programs, there
are no acceptable workarounds that could adequately compensate for its
absence.)

And, technically, I do not see any implementation problem with
_exit_immediately(). All threading libraries that I have seen can
implement it without difficulty: the first thread that calls
_exit_immediately() acquires a shutdown lock, clears out the global
destructor table (or atexit handler, or whatever), calls the scheduler
to preempt all running threads, and then dismantles the process as
usual.

>>> I have always found that programs that somehow has destructors that
>>> can fail need to have their design reevaluated.
>>
>> I believe that to be a gross generalization.
>
> No it isn't. Much of C++ is designed on the implicit assumption that
> dtors do not fail. If you find such dtors necessary then solving the
> resulting problems is entirely your problem :-)

I have to differ. There are a few problems that can be solved only
with global objects, such as aggregating type information
across different compilation units. Because of dynamic loading of
libraries, this cannot be done statically and must happen at run time.
And because threads may involved, that requires locking, which can
cause the deadlock problem if exit() is called at the wrong moment.

You may also want to have a look at another thread in this group:

http://tinyurl.com/2ablax

Here, the problem is caused by a std::ostream destructor. So it
would appear that the standard library would need its design
reevaluated too (which I don't think is the case--all that is
needed is _exit_immediately()).

And I believe it is reasonable to ask for a function that simply
makes my process go away, especially when considering the difficulty
of implementing this behavior myself for a program that also links
against third-party libraries about whose inner workings I know
nothing.

Cheers,

Michi.

--

Michi Henning

unread,
Aug 16, 2007, 6:30:35 AM8/16/07
to
Bjørn Roald wrote:

> That Ice or other middleware libs use threads are perfectly Ok. But
> they should not manage the threads in a way hidden to the application.
> Further, the control of the threads should not be beyond the reach of
> the application code. If I was using Ice, and I have been considering
> it as it seems to be very nice, I would prefer to create, own, and
> manage all the threads myself.

Hmmm... I see what you mean. On the other hand, doing what you suggest
would make the APIs and interactions with the application more complex
(a *lot* more complex, in fact). Now, is that really the right way to
go *just* so the application can safely exit?


> The threading and concurrency model of my
> application would then be completely in my control. At a minimum, Ice
> should provide me with the option of having such control of the
> threading in my application.

Ice provides quite a few concurrency models, and allows these models
to be configured in various ways, such as using a thread per connection,
changing the number of threads in various pools, or run single-threaded.
But all of this is achievable very simply, without the need to give
the application access to every thread handle in the run time. And,
besides, doing this would *not* solve the problem. There is still
the issue of how to preempt threads, get them to terminate, get them
out of blocking system calls or out of condvars they are sleeping on,
etc. And not all threading packages support cancellation. So, I don't
see how doing all this would substantially alter the picture (other
than add a lot of complexity).

> By the way, have you studied asynchron I/O methods in Boost::Asio as an
> alternative or addition to threading?

Ice already supports asynchronous I/O (not via Boost::Asio though).

>> In general, there are good and legitimate reasons for libraries to
>> create global objects (just think of cin, cout, and cerr), and for
>> libraries to create threads. These reasons won't go away and, without
>> some help from the spec, I can't see how a program linking against
>> such a library can terminate safely.
>
> If I am not mistaken, cout etc. are references to the global objects.
> I.e. I do not have to use them, I can "redirect" to any compatible
> stream/streambuff object in my application. Hence, I have control.

I guess that is true: I don't have to use cin, cout, or cerr, or any
iostreams at all, for that matter. I would prefer to able to use them
though *without* running the risk of a deadlock if I want to terminate
the program.

>> I am the author of that library :-) And, believe me, there is no way
>> for the application to shut down that library from a signal handling
>> context that isn't unspeakably messy, other than calling _exit().
>> And _exit() works fine in practice, except that the standard does not
>> guarantee me that it will...
>
> At this point I am slightly confused. I do not know if it matters for
> the discussion, but is your concern that there not possible to provide a
> library as Ice with a clean way for applications using it to shut down?

More or less. Basically, if a library uses threads, and the application
wants to terminate for some reason, and wants to do it suddenly (such as
from a signal handler) doing this is currently not possible without
relying on implementation dependent behavior. (This is true even without
threads.)

All I am saying is that the standard should provide a function that
guarantees that I'll be able to exit at any time without undefined
behavior. That's not a big thing to ask for, and it is pragmatically
useful, so why not add it?

> As I pointed out before, using _Exit() or _exit() may work Ok on some
> platforms and for some applications, but I do not think it is a good
> clean shut-down that I ever would recommend in general. I think it is
> possible for Ice to do better. One often simple approach is to make the
> core issues a problem for the application, not something you need to
> solve in the library. I think some problems become very hard to do
> right if you insist on solving them hidden deep in the library.

At the cost of more complex APIs, more complex documentation, and
additional learning curve on part of the users of the library. This does
not strike me as good tradeoff.

Cheers,

Michi.


--

Francis Glassborow

unread,
Aug 16, 2007, 2:52:41 PM8/16/07
to
Michi Henning wrote:
> All I am saying is that the standard should provide a function that
> guarantees that I'll be able to exit at any time without undefined
> behavior. That's not a big thing to ask for, and it is pragmatically
> useful, so why not add it?
>
You may not think it is a big thing to ask for, however it is or we
would have provided it a long time back.


--
Note that robinton.demon.co.uk addresses are no longer valid.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Francis Glassborow

unread,
Aug 16, 2007, 2:52:22 PM8/16/07
to
Michi Henning wrote:
> Francis Glassborow wrote:
>> Michi Henning wrote:
>>>
>>> Theoretically, I could do all this. But should it really be necessary
>>> to have to jump through all those hoops just to make a process terminate
>>> without dumping core? Why can't the standard simply provide me with a
>>> function call that terminates the process immediately and without
>>> further ado? That way, I wouldn't have to do any of these things and
>>> could simply call _exit_immediately() (or whatever it would be called).
>>
>> Of course providing such may seem very easy, but believe me it is taking
>> a group of world class language experts a great deal of time to specify
>> exactly how that should be supported in the next version of C++.
>> Threading, particularly on multi-core machines, is very far from trivial.
>
> I know that it's not trivial :-) But, just because it may be difficult
> to specify _exit_immediately() doesn't mean that it shouldn't be
> specified. The only thing that should matter is whether it is needed.
> (Personally, I believe it *is* needed because, for some programs, there
> are no acceptable workarounds that could adequately compensate for its
> absence.)

Which is why so much effort is going into trying to ensure that we get
it right.


>
> And, technically, I do not see any implementation problem with
> _exit_immediately(). All threading libraries that I have seen can
> implement it without difficulty: the first thread that calls
> _exit_immediately() acquires a shutdown lock, clears out the global
> destructor table (or atexit handler, or whatever), calls the scheduler
> to preempt all running threads, and then dismantles the process as
> usual.

But a Standard has to cope across all reasonable hardware and the rules
have substantially changed with the move to multi-core machines where
threads can genuinely run in parallel. I heard one expert say publicly
in a keynote at a conference that the fact that our multi-threading
software seemed to work in the past was more by luck than by design.

When your computer crashes or a process refuses to exit once in a while
who do you blame? The hardware? the OS? or failed multi-threading?

>
>>>> I have always found that programs that somehow has destructors that
>>>> can fail need to have their design reevaluated.
>>>
>>> I believe that to be a gross generalization.
>>
>> No it isn't. Much of C++ is designed on the implicit assumption that
>> dtors do not fail. If you find such dtors necessary then solving the
>> resulting problems is entirely your problem :-)
>
> I have to differ. There are a few problems that can be solved only
> with global objects, such as aggregating type information
> across different compilation units. Because of dynamic loading of
> libraries, this cannot be done statically and must happen at run time.
> And because threads may involved, that requires locking, which can
> cause the deadlock problem if exit() is called at the wrong moment.

What has this got to do with failing dtors. A dtor that throws leaves a
ghost object, and one that often has lost its base memory into the
bargain. A dtor that throws is an accident waiting to happen.

>
> You may also want to have a look at another thread in this group:
>
> http://tinyurl.com/2ablax

sorry but I do not see what that has to do with throwing from a dtor (or
not doing so)

>
> Here, the problem is caused by a std::ostream destructor. So it
> would appear that the standard library would need its design
> reevaluated too (which I don't think is the case--all that is
> needed is _exit_immediately()).

And the Standard library is in the process of very substantial reworking
partly as a result of incorporating threads. This is a mammoth amount
of work being undertaken by volunteers. Indeed the work is so
substantial that it will almost certainly cause a delay in shipping the
C++0x.

If you genuinely believe that all that is needed is _exit_immediately()
then you really do not understand the problems of MT running on
concurrent processors.

>
> And I believe it is reasonable to ask for a function that simply
> makes my process go away, especially when considering the difficulty
> of implementing this behavior myself for a program that also links
> against third-party libraries about whose inner workings I know
> nothing.

It may be reasonable to ask, but granting your request is far from being
do it now. The whole issue of MT, multi-threading etc. is so complex
that it has resulted in extra ad-hoc meetings of the relevant experts in
order to get it right. Yes, we will, I believe, get it right but not
just by wishful thinking.

>
> Cheers,
>
> Michi.
>


--
Note that robinton.demon.co.uk addresses are no longer valid.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Chris Thomasson

unread,
Aug 17, 2007, 3:25:33 AM8/17/07
to
"Francis Glassborow" <francis.g...@btinternet.com> wrote in message
news:0Y2dndatsbFu1Fnb...@bt.com...
[...]

> It may be reasonable to ask, but granting your request is far from being
> do it now. The whole issue of MT, multi-threading etc. is so complex
> that it has resulted in extra ad-hoc meetings of the relevant experts in
> order to get it right. Yes, we will, I believe, get it right but not
> just by wishful thinking.

[...]

Yup. The standard will be successfully augmented with threads because of the
fine work that is occurring over on the cpp-threads mailing list. They have
talented people, like Paul McKenney, who knows a _thing or two_ about
developing and integrating high-end concurrent programming techniques into
real-world applications. I am glad to see that the talent who invented RCU
is getting to have his say in the relevant discussions!

There is no way that the standard will not allow one to program portable RCU
once the cpp-threads group gets through with it. Well, SC is okay, but I
need relaxed atomics to feel comfortable. Luckily, it looks like there is
going to be some rather robust support for relaxed/weak atomic-operations.
SC will be available for those who need it, and the speedy functions will be
standardized for those who know to use them correctly.

;^)


--

Dilip

unread,
Aug 17, 2007, 3:22:25 AM8/17/07
to
On Aug 16, 5:30 am, Michi Henning <mi...@zeroc.com> wrote:

> > Michi Henning wrote:
>
> And, technically, I do not see any implementation problem with
> _exit_immediately(). All threading libraries that I have seen can
> implement it without difficulty: the first thread that calls
> _exit_immediately() acquires a shutdown lock, clears out the global
> destructor table (or atexit handler, or whatever), calls the scheduler
> to preempt all running threads, and then dismantles the process as
> usual.

Daniel Krugler posted this[1] at comp.std.c++. It doesnt' help you
right away but at least the issue is being addressed.

Direct link to proposal:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2383.html

[1] http://groups.google.com/group/comp.std.c++/msg/9e77ba715cc46bc6

Michi Henning

unread,
Aug 17, 2007, 3:25:57 AM8/17/07
to
Francis Glassborow wrote:
>
> If you genuinely believe that all that is needed is _exit_immediately()
> then you really do not understand the problems of MT running on
> concurrent processors.
>
>>
>> And I believe it is reasonable to ask for a function that simply
>> makes my process go away, especially when considering the difficulty
>> of implementing this behavior myself for a program that also links
>> against third-party libraries about whose inner workings I know
>> nothing.
>
> It may be reasonable to ask, but granting your request is far from being
> do it now. The whole issue of MT, multi-threading etc. is so complex
> that it has resulted in extra ad-hoc meetings of the relevant experts in
> order to get it right. Yes, we will, I believe, get it right but not
> just by wishful thinking.

You may find the following proposal of interest, which addresses exactly
the problem I raised and solves it very nicely:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2383.html

quick_exit() is exactly what I'm looking for.

Cheers,

Michi.

--

Francis Glassborow

unread,
Aug 17, 2007, 11:52:29 AM8/17/07
to
Michi Henning wrote:
> Francis Glassborow wrote:
>>
>> If you genuinely believe that all that is needed is _exit_immediately()
>> then you really do not understand the problems of MT running on
>> concurrent processors.
>>
>>>
>>> And I believe it is reasonable to ask for a function that simply
>>> makes my process go away, especially when considering the difficulty
>>> of implementing this behavior myself for a program that also links
>>> against third-party libraries about whose inner workings I know
>>> nothing.
>>
>> It may be reasonable to ask, but granting your request is far from being
>> do it now. The whole issue of MT, multi-threading etc. is so complex
>> that it has resulted in extra ad-hoc meetings of the relevant experts in
>> order to get it right. Yes, we will, I believe, get it right but not
>> just by wishful thinking.
>
> You may find the following proposal of interest, which addresses exactly
> the problem I raised and solves it very nicely:
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2383.html
>
> quick_exit() is exactly what I'm looking for.

FOFL, yes indeed and it has already consumed many hours of discussion
and addressing all kinds of gotchas. Do you think that I wrote the above
without knowing what WG21 is doing? After all I have been Head of the UK
delegation to WG21 for over a decade and was one of the principle voices
advocating the need for a new memory model to cope with true parallel
processing. No, I am far from being an expert in that field but could
see what was coming down the line and the need to cater for it.


--
Note that robinton.demon.co.uk addresses are no longer valid.

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Maxim Yegorushkin

unread,
Aug 17, 2007, 4:19:35 PM8/17/07
to
On 6 Aug, 06:36, Michi Henning <mi...@zeroc.com> wrote:
> I'm in the situation where I need to terminate a threaded program
> from within a signal handler. I cannot call exit() because global
> destructors may find data structures in an inconsistent state
> and crash, or may deadlock on various mutexes. So, I'm calling _exit()
> instead, which (at least for many implementations) prevents global
> destructors from running.

Looking at the problem in a larger scope, terminating the application
with 3rd party libraries without giving them a chance to execute clean-
up routines leaves your execution environment in undefined state. One
example is when a library allocates POSIX named shared memory, whose
filesystem name is supposed to be unlink()ed on exit(). Not giving it
a chance to unlink() leaks operating system resources (the ones that
have lifetime scope longer than that of a program).

[...]

> The worrying thing is that the standard doesn't say anything about
> exit() or _exit(), so I'm relying on implementation-dependent behavior.
> Note that the problem also arises for non-threaded programs: in general,
> it is not safe to call exit() from a signal handler because that might
> cause undefined behavior (because data structure may be in an
> inconsistent state, causing destructors to fall over). _exit()
> usually works, but does not exist as far as the standard is concerned.

Signal handlers are notorious for being a bad place to do any calls,
apart from a small list of async-signal safe functions (see the list
at the bottom of
http://www.opengroup.org/onlinepubs/000095399/functions/xsh_chap02_04.html#t
ag_02_04).
The solution is to defer the work to normal (as opposed to signal)
execution context, what is usually done by self-pipe trick (http://
cr.yp.to/docs/selfpipe.html): having the signal handler write a byte
into a pipe, which is later read by some other thread. Having read the
pipe, that thread would make the other threads shutdown gracefully and
conclude by making the main thread leave main(). It is easily
achievable on practice even with 3rd party libraries, since they
normally provide library init/deinit functions or (reference counted)
library init objects.

The root of the problem is the assumption that terminating directly
from a signal handler is a good idea. This idea ignores the existing
good practices and leads to the necessity of having a quick exit
function (may be with at-quick-exit handlers), which is, IMHO, an ugly
language hack. The real solution is to not terminate from the signal
handler, rather defer that job for normal execution context. From the
normal context you can terminate gracefully while having available all
the standard C++ facilities, such as destructors.

--

Le Chaud Lapin

unread,
Aug 18, 2007, 6:06:53 AM8/18/07
to
On Aug 17, 3:19 pm, Maxim Yegorushkin <maxim.yegorush...@gmail.com>
wrote:

> Signal handlers are notorious for being a bad place to do any calls,
> apart from a small list of async-signal safe functions (see the list
> at the bottom ofhttp://www.opengroup.org/onlinepubs/000095399/functions/xsh_chap02_04...

> ag_02_04).
> The solution is to defer the work to normal (as opposed to signal)
> execution context, what is usually done by self-pipe trick (http://
> cr.yp.to/docs/selfpipe.html): having the signal handler write a byte
> into a pipe, which is later read by some other thread. Having read the
> pipe, that thread would make the other threads shutdown gracefully and
> conclude by making the main thread leave main(). It is easily
> achievable on practice even with 3rd party libraries, since they
> normally provide library init/deinit functions or (reference counted)
> library init objects.

This seems like a nice approach.

I have never used the self-pipe trick, but the "make the other threads
shutdown gracefully", I do have a bit of experience with which I
wanted to talk about here.

Win32 programmers will be familiar with the WaitForSingleObject and
WaitForMultipleObject functions. WaitForMultipleObject is not used as
much as WaitForSingleObject, but it is precisely what is called for to
help with the OP's scenario.

Note that, although these functions are OS-specific, the principles
behind them are not. IOW, it might turn out that, in the Grand
Architecture of Multithreading, these functions will be semantically
fundamental across all operating systems. That said, all one needs to
do is wrap them in the appropriate C++ classes and make the classes
portable.

When that is done, it becomes easy for a thread to wait for multiple
things. One might create a list of pointers to those things, and
provide a function that and wait on the entire list, allowing a thread
to wait on:

1. whatever it normally waits on if it is waiting at all,

and, *simultaneously*

2. a signal from the signal-handler, or rather, its proxy using the
self-pipe trick, that the thread should die

As the thread dies, the regular C++ destructor mechanisms come into
play.

I have experimented with this model quite a bit and I would give it an
A+ the "feels right" category. Like the notion of a stack in function
calls, after a few uses, it becomes so second-nature that one forgets
the complexity occurring behind the scenes.

-Le Chaud Lapin-

Bjørn Roald

unread,
Aug 18, 2007, 1:13:46 PM8/18/07
to
Michi Henning wrote:
> Bjørn Roald wrote:
>
>> That Ice or other middleware libs use threads are perfectly Ok. But
>> they should not manage the threads in a way hidden to the application.
>> Further, the control of the threads should not be beyond the reach of
>> the application code. If I was using Ice, and I have been considering
>> it as it seems to be very nice, I would prefer to create, own, and
>> manage all the threads myself.
>
> Hmmm... I see what you mean. On the other hand, doing what you suggest
> would make the APIs and interactions with the application more complex
> (a *lot* more complex, in fact). Now, is that really the right way to
> go *just* so the application can safely exit?

Hmmm... Interesting choice of emphasized words. It is easy to turn
these completely around and make them equally valid. Having only the
simple API may make things a *lot* more complicated in some use-cases.
I have the feeling that is the crux of this thread. And that is *just*
because you are too concerned about the beauty and elegance of the API.

Leaving decomposing food in sealed boxes deep in your fridge may not
smell or look bad until *have* to deal with it. Your proposed
(quick_exit) solution is dealing with it by flushing everything in the
fridge in a giant toilette without any regard what else is in there. If
you care about what is in there, you may have to methodically check
every box's contents, clean up reusable items and place them back in the
your kitchen's operation environment. That is what C++ deconstructors
is about.

Even if the application is shutting down and many operating environments
reclaim resources automatically, this is not always a complete solution
for all applications. Many resources are not properly managed by
typical OS's process cleanup. Using C++ without the language asserting
that the destructors will be executed feels wrong, and it smells bad.
There have to be a better way. Somehow letting the signal handler pass
control back to the application so a more normal shutdown can commence
seems a lot better. I am not saying that there are not a lot of
applications which something like quick_exit() is perfectly Ok, but that
should be up too the application - not a library to decide.

>> The threading and concurrency model of my
>> application would then be completely in my control. At a minimum, Ice
>> should provide me with the option of having such control of the
>> threading in my application.
>
> Ice provides quite a few concurrency models, and allows these models
> to be configured in various ways, such as using a thread per connection,
> changing the number of threads in various pools, or run single-threaded.
> But all of this is achievable very simply, without the need to give
> the application access to every thread handle in the run time.

What is wrong with giving access, you do not have to force applications
to use them. If that access is real help to 0.5% of the applications
using Ice, it may be worth it.

> And,
> besides, doing this would *not* solve the problem. There is still
> the issue of how to preempt threads, get them to terminate, get them
> out of blocking system calls or out of condvars they are sleeping on,
> etc.

This seems to me as an application problem, hopefully it is not a
library problem. Libraries should be carefully crafted so they do not
prevent applications from dealing with their own issues.

> And not all threading packages support cancellation. So, I don't
> see how doing all this would substantially alter the picture (other
> than add a lot of complexity).

Applications may have POSIX at their disposal, the fact that Ice can not
count on it is not something applications should *have* to be concerned
about.

>> By the way, have you studied asynchron I/O methods in Boost::Asio as an
>> alternative or addition to threading?
>
> Ice already supports asynchronous I/O (not via Boost::Asio though).

Good :-)

>>> I am the author of that library :-) And, believe me, there is no way
>>> for the application to shut down that library from a signal handling
>>> context that isn't unspeakably messy, other than calling _exit().
>>> And _exit() works fine in practice, except that the standard does not
>>> guarantee me that it will...
>>
>> At this point I am slightly confused. I do not know if it matters for
>> the discussion, but is your concern that there not possible to provide a
>> library as Ice with a clean way for applications using it to shut down?
>
> More or less. Basically, if a library uses threads, and the application
> wants to terminate for some reason, and wants to do it suddenly (such as
> from a signal handler) doing this is currently not possible without
> relying on implementation dependent behavior. (This is true even without
> threads.)
>
> All I am saying is that the standard should provide a function that
> guarantees that I'll be able to exit at any time without undefined
> behavior. That's not a big thing to ask for, and it is pragmatically
> useful, so why not add it?

This make sense to me as well, as long as Ice or other libriaries does
not force applications into using such solutions.

There is however a big question here that needs addressing. The term
"undefined behavior" is the opposite of defined. You seem to be
concerned only that the return value and termination of process threads
should be defined. But it is beyond me how you think skipping
destructors in general render defined behavior.

>> As I pointed out before, using _Exit() or _exit() may work Ok on some
>> platforms and for some applications, but I do not think it is a good
>> clean shut-down that I ever would recommend in general. I think it is
>> possible for Ice to do better. One often simple approach is to make the
>> core issues a problem for the application, not something you need to
>> solve in the library. I think some problems become very hard to do
>> right if you insist on solving them hidden deep in the library.
>
> At the cost of more complex APIs, more complex documentation, and
> additional learning curve on part of the users of the library. This does
> not strike me as good tradeoff.

Just try to make sure you do not make it harder than needed by ignoring
real issues. The API should be simple, but not too simple. I am a fan
of separating the more complex API used by a few specialist users from
the common simple API in such a way that the typical user does not have
to deal with complex issues unless they have too.

--
regards
Bjørn

Michi Henning

unread,
Aug 22, 2007, 8:13:01 AM8/22/07
to
Bjørn Roald wrote:
>
> Even if the application is shutting down and many operating environments
> reclaim resources automatically, this is not always a complete solution
> for all applications. Many resources are not properly managed by
> typical OS's process cleanup. Using C++ without the language asserting
> that the destructors will be executed feels wrong, and it smells bad.
> There have to be a better way. Somehow letting the signal handler pass
> control back to the application so a more normal shutdown can commence
> seems a lot better. I am not saying that there are not a lot of
> applications which something like quick_exit() is perfectly Ok, but that
> should be up too the application - not a library to decide.

I agree that, at least in general, orderly shutdown is preferable. But
there are situations where that is simply not practical. I don't think
C++ should dictate to me how I can or cannot terminate my program. If
I call quick_exit() on a platform that won't clean up resources, I
deserve what I get. (I *want* the program to exit immediately and
without further ado--if I don't want that, I can call exit() instead.)

>> And,
>> besides, doing this would *not* solve the problem. There is still
>> the issue of how to preempt threads, get them to terminate, get them
>> out of blocking system calls or out of condvars they are sleeping on,
>> etc.
>
> This seems to me as an application problem, hopefully it is not a
> library problem. Libraries should be carefully crafted so they do not
> prevent applications from dealing with their own issues.

I don't follow that. Suppose the *application* has decided that it wants
to terminate, for whatever reason. Complicating the APIs and forcing the
application to make all sorts of library calls before it can terminate
seems awkward to me, not to mention the difficulty of actually
implementing such functionality, especially on platforms that don't
provide thread cancellation.

>> And not all threading packages support cancellation. So, I don't
>> see how doing all this would substantially alter the picture (other
>> than add a lot of complexity).
>
> Applications may have POSIX at their disposal, the fact that Ice can not
> count on it is not something applications should *have* to be concerned
> about.

Sorry, I again don't follow that. Several people argued that it is up to
me to orchestrate my library such that an application can instruct the
library to terminate in some orderly way and then safely call exit().
I keep pointing out that not all threading libraries support
cancellation, so this can be impossible to implement. What am I (or
the application) supposed to do in this scenario? In effect, without
something like quick_exit(), this would mean that C++ cannot be used
in such environments? Or it means that exiting from within a signal
handler has undefined behavior?

>>>> I am the author of that library :-) And, believe me, there is no way
>>>> for the application to shut down that library from a signal handling
>>>> context that isn't unspeakably messy, other than calling _exit().
>>>> And _exit() works fine in practice, except that the standard does not
>>>> guarantee me that it will...
>>>
>>> At this point I am slightly confused. I do not know if it matters for
>>> the discussion, but is your concern that there not possible to provide a
>>> library as Ice with a clean way for applications using it to shut down?

There are ways to cleanly shut down the Ice run time, of course. But,
from a signal-handling context, that is basically not possible because
hardly anything is async-signal-safe. The application would have to
set a flag in the signal handler, poll that flag, then shut down the run
time, then exit. Why force the application to jump through all these
hoops when, really, all it wants to do is go away?

>> All I am saying is that the standard should provide a function that
>> guarantees that I'll be able to exit at any time without undefined
>> behavior. That's not a big thing to ask for, and it is pragmatically
>> useful, so why not add it?
>
> This make sense to me as well, as long as Ice or other libriaries does
> not force applications into using such solutions.

Agree. For Ice, the application can call an API function to shut down
the Ice run time in an orderly fashion any time it likes, *except* from
within a signal handler.

> There is however a big question here that needs addressing. The term


> "undefined behavior" is the opposite of defined. You seem to be
> concerned only that the return value and termination of process threads
> should be defined. But it is beyond me how you think skipping
> destructors in general render defined behavior.

*Executing* destructors can cause undefined behavior, because those
destructors may access a data structure that is in an inconsistent state
(such as when exit() is called from a signal handler in a
single-threaded program), or the destructors may deadlock (if exit() is
called from an arbitrary thread in a threaded program, because the
destructors may need to acquire locks).

Skipping destructors for objects with static storage duration renders
defined behavior because (as with quick_exit()), the spec would simply
say that the process disappears and no destructors are called. So
the code in destructors cannot cause undefined behavior because that
code never runs.

>> At the cost of more complex APIs, more complex documentation, and
>> additional learning curve on part of the users of the library. This does
>> not strike me as good tradeoff.
>
> Just try to make sure you do not make it harder than needed by ignoring
> real issues. The API should be simple, but not too simple. I am a fan
> of separating the more complex API used by a few specialist users from
> the common simple API in such a way that the typical user does not have
> to deal with complex issues unless they have too.

Totally agree with that. But I'm not going to add any complexity
whatsoever to the Ice API (let alone a whole pile of complex
machinery to orchestrate shutdown that may be unimplementable on some
platforms anyway) just so a process can exit without dumping core or
deadlocking.

To put this differently: I think it would be wrong for C++ to dictate
to me how I have to structure my threading, force me to provide
complex shutdown machinery, or make my library's thread handles
accessible to the application just so an application can exit.

Cheers,

Michi.


--

Matthew Newhook

unread,
Aug 22, 2007, 8:15:48 AM8/22/07
to
On Aug 19, 1:13 am, Bjørn Roald <bj...@4roald.org> wrote:
> > Ice provides quite a few concurrency models, and allows these models
> > to be configured in various ways, such as using a thread per connection,
> > changing the number of threads in various pools, or run single-threaded.
> > But all of this is achievable very simply, without the need to give
> > the application access to every thread handle in the run time.
>
> What is wrong with giving access, you do not have to force applications
> to use them. If that access is real help to 0.5% of the applications
> using Ice, it may be worth it.

Just to be clear -- the application can get access to the Ice runtime
threads. However, I'm not sure what this has to do with this
particular discussion.

--

Michi Henning

unread,
Aug 22, 2007, 8:13:24 AM8/22/07
to
Maxim Yegorushkin wrote:
>
> Looking at the problem in a larger scope, terminating the application
> with 3rd party libraries without giving them a chance to execute clean-
> up routines leaves your execution environment in undefined state. One
> example is when a library allocates POSIX named shared memory, whose
> filesystem name is supposed to be unlink()ed on exit(). Not giving it
> a chance to unlink() leaks operating system resources (the ones that
> have lifetime scope longer than that of a program).

Yes. But when I know that my program doesn't need to clean up any
such resources, I should be allowed to terminate the program. In fact,
even when there are such resources, the decision as to whether I want
them to be cleaned should be left to me and not be imposed by the
language.


> Signal handlers are notorious for being a bad place to do any calls,
> apart from a small list of async-signal safe functions (see the list
> at the bottom of
> http://www.opengroup.org/onlinepubs/000095399/functions/xsh_chap02_04.html#t
> ag_02_04).
> The solution is to defer the work to normal (as opposed to signal)
> execution context, what is usually done by self-pipe trick (http://
> cr.yp.to/docs/selfpipe.html): having the signal handler write a byte
> into a pipe, which is later read by some other thread. Having read the
> pipe, that thread would make the other threads shutdown gracefully and
> conclude by making the main thread leave main(). It is easily
> achievable on practice even with 3rd party libraries, since they
> normally provide library init/deinit functions or (reference counted)
> library init objects.

Yes, I'm aware of the self-pipe trick, and Ice uses it too. But I should
not be forced to use this (or any other trick) just so my program can
terminate. And, as I keep pointing out, with libraries that do not
support thread cancellation, I cannot see any trick at all that would
achieve this.

> The root of the problem is the assumption that terminating directly
> from a signal handler is a good idea. This idea ignores the existing
> good practices and leads to the necessity of having a quick exit
> function (may be with at-quick-exit handlers), which is, IMHO, an ugly
> language hack. The real solution is to not terminate from the signal
> handler, rather defer that job for normal execution context. From the
> normal context you can terminate gracefully while having available all
> the standard C++ facilities, such as destructors.

I know all this. But I don't see why I should have the design of my
application dictated to me by the language, especially when all I want
to do is make a process disappear.

Cheers,

Michi.

Matthew Newhook

unread,
Aug 22, 2007, 8:20:22 AM8/22/07
to
{ Edits: quoted banner removed. Please don't quote the banner. Tip:
decent newsreader programs remove the banner automatically. -mod }

On Aug 18, 4:19 am, Maxim Yegorushkin <maxim.yegorush...@gmail.com>
wrote:


> The root of the problem is the assumption that terminating directly
> from a signal handler is a good idea. This idea ignores the existing
> good practices and leads to the necessity of having a quick exit
> function (may be with at-quick-exit handlers), which is, IMHO, an ugly
> language hack. The real solution is to not terminate from the signal
> handler, rather defer that job for normal execution context. From the
> normal context you can terminate gracefully while having available all
> the standard C++ facilities, such asdestructors.

Terminating from a signal handler is a red-herring when it comes to
this discussion. From within the application context you also may not
be able to terminate gracefully. If another thread of control is stuck
in a system call, what do you do then? Politely ask it to go away? I'm
afraid not.

Bjørn Roald

unread,
Aug 22, 2007, 9:05:50 PM8/22/07
to
Matthew Newhook wrote:
> On Aug 19, 1:13 am, Bjørn Roald <bj...@4roald.org> wrote:
>>> Ice provides quite a few concurrency models, and allows these models
>>> to be configured in various ways, such as using a thread per connection,
>>> changing the number of threads in various pools, or run single-threaded.
>>> But all of this is achievable very simply, without the need to give
>>> the application access to every thread handle in the run time.
>> What is wrong with giving access, you do not have to force applications
>> to use them. If that access is real help to 0.5% of the applications
>> using Ice, it may be worth it.
>
> Just to be clear -- the application can get access to the Ice runtime
> threads. However, I'm not sure what this has to do with this
> particular discussion.

Ok, access to the threads is available. That is good. But I guess
Michi's point was that the user does not need to mess with the threads
directly to manage threading and concurrency within Ice.

--
Bjørn

Bjørn Roald

unread,
Aug 22, 2007, 9:05:06 PM8/22/07
to
Michi Henning wrote:
> Bjørn Roald wrote:
>>
>> Even if the application is shutting down and many operating environments
>> reclaim resources automatically, this is not always a complete solution
>> for all applications. Many resources are not properly managed by
>> typical OS's process cleanup. Using C++ without the language asserting
>> that the destructors will be executed feels wrong, and it smells bad.
>> There have to be a better way. Somehow letting the signal handler pass
>> control back to the application so a more normal shutdown can commence
>> seems a lot better. I am not saying that there are not a lot of
>> applications which something like quick_exit() is perfectly Ok, but that
>> should be up too the application - not a library to decide.
>
> I agree that, at least in general, orderly shutdown is preferable. But
> there are situations where that is simply not practical.

Agree, I think the only disagreement we may have is to what degree a
library should or should not dictate the solution that is used. I
clearly think it should not, just as little as the C++ language should
limit the options.

> I don't think
> C++ should dictate to me how I can or cannot terminate my program. If
> I call quick_exit() on a platform that won't clean up resources, I
> deserve what I get. (I *want* the program to exit immediately and
> without further ado--if I don't want that, I can call exit() instead.)

Agree again. However, as long as a library I use force me too use a
specific method or limit my options, then it would become irrelevant if
C++ offered something the library denied me to use in my application.

>>> And,
>>> besides, doing this would *not* solve the problem. There is still
>>> the issue of how to preempt threads, get them to terminate, get them
>>> out of blocking system calls or out of condvars they are sleeping on,
>>> etc.
>>
>> This seems to me as an application problem, hopefully it is not a
>> library problem. Libraries should be carefully crafted so they do not
>> prevent applications from dealing with their own issues.
>
> I don't follow that. Suppose the *application* has decided that it wants
> to terminate, for whatever reason.

Simple and clean ways to shut down is all that is needed. If the API
provide that, then it is e mistake to replace it with a complicated
involved system. For the usual use-cases where simple shutdown is
needed the library should provide simple API. I am not trying to
convince you or anybody else that what is good and works well in Ice or
any other library shall be replaced with something that is more
complicated to use. If you think so, then I must have been unclear.

> Complicating the APIs and forcing the
> application to make all sorts of library calls before it can terminate
> seems awkward to me,

Yes, too me as well. What I am trying to say is that some times one
become too eager making nice API handling 98% of the use-cases one
promise to solve. In the process one forget or ignore making workable
API for the remaining 2%. If I in my application am stuck within the
last 2%, then I tend to send nasty thoughts towards the library
designers for ignoring me. I have no desire for complicated API in its
own, if the API is simple and solve the last 2% as well, then that is
the best way. If more complex solution is needed, then offer this as
optional API, do not mess up the primary API.

> not to mention the difficulty of actually
> implementing such functionality, especially on platforms that don't
> provide thread cancellation.

This does not mean anything to me, sorry. Are you expecting it to be
simpler to solve it hidden within your library than it is to give up and
give applications access to raw features so the application can try to
solve it in their context? If that is the case, surely it is a mistake
to complicate the API to let applications do something the library has a
solution for.

If however there are important use-cases, which the library does not
solve in a portable way. Then it is a mistake not to give the API
features so applications can have more direct control and possibly
utilize platform specific features including other good libraries.

>>> And not all threading packages support cancellation. So, I don't
>>> see how doing all this would substantially alter the picture (other
>>> than add a lot of complexity).
>>
>> Applications may have POSIX at their disposal, the fact that Ice can not
>> count on it is not something applications should *have* to be concerned
>> about.
>
> Sorry, I again don't follow that. Several people argued that it is up to
> me to orchestrate my library such that an application can instruct the
> library to terminate in some orderly way and then safely call exit().

If you are not able to do that, then I add: You should carefully design
your API to at least provide application with the means to attempt to
solve what the library designers gave up solving. The only other good
option is to go open source with the critical parts of the library or
all of it if. This is of cause not always feasible.

> I keep pointing out that not all threading libraries support
> cancellation, so this can be impossible to implement.

In addition e.g. POSIX threads cancellation does not say anything about
C++ destructors, so what does that help unless something else on the
platform make relevant guaranties. Unless my memory fails in undefined
ways I think Sun CC on Solaris documents that canceled threads will
unwind call stacks, including execution of C++ destructors. But this is
not given on any pthread + Std C++ platform.

Nevertheless, you may decide that Ice can not depend on cancellation
support and proper cleanup in its wake. That is perfectly OK as long as
you allow Ice users that option. I can if I am on certain platforms
decide to depend on cancellation if Ice give me ways of managing the
threads as pthread threads.

> What am I (or
> the application) supposed to do in this scenario? In effect, without
> something like quick_exit(), this would mean that C++ cannot be used
> in such environments?

Exiting with the proposed quick_exit() define some aspects of that
shut-down, but certainly not all aspects. So exiting with quick_exit()
is in many respects undefined as well. The question is what you care
about being defined. The application should be able to choose.

> Or it means that exiting from within a signal
> handler has undefined behavior?

Well it may be hard or very hard to avoid all undefined behavior if you
have a stack overflow, an access violation, etc. But it can be
minimized with some effort. However, if I as user press Ctrl-C on the
keyboard to signal a server to shut down, then quick_exit() may be a
very bad choice for the relevant signal handler in the server.

>>>>> I am the author of that library :-) And, believe me, there is no way
>>>>> for the application to shut down that library from a signal handling
>>>>> context that isn't unspeakably messy, other than calling _exit().
>>>>> And _exit() works fine in practice, except that the standard does not
>>>>> guarantee me that it will...
>>>>
>>>> At this point I am slightly confused. I do not know if it matters for
>>>> the discussion, but is your concern that there not possible to
>>>> provide a
>>>> library as Ice with a clean way for applications using it to shut down?
>
> There are ways to cleanly shut down the Ice run time, of course. But,
> from a signal-handling context, that is basically not possible because
> hardly anything is async-signal-safe. The application would have to
> set a flag in the signal handler, poll that flag, then shut down the run
> time, then exit. Why force the application to jump through all these
> hoops when, really, all it wants to do is go away?

It is not a question of forcing, but more of giving the option of other
solutions than quick_exit(). If the application is OK with using
quick_exit(), _Exit(), abort(), or some async notify to normal flow and
return in the signal handler, then that is all OK. All I am trying to
get out is that a library should not enforce a specific way as little as
the language should.

I think really we may agree on this, it feels like we are just threading
water here. It is not always fully clear to me when your statements
apply to use-cases of Ice in applications, or when they apply to
attempts to implement features within the Ice product. That may have
confused me and I might have responded in ways confusing you.

>>> All I am saying is that the standard should provide a function that
>>> guarantees that I'll be able to exit at any time without undefined
>>> behavior. That's not a big thing to ask for, and it is pragmatically
>>> useful, so why not add it?
>>
>> This make sense to me as well, as long as Ice or other libriaries does
>> not force applications into using such solutions.
>
> Agree. For Ice, the application can call an API function to shut down
> the Ice run time in an orderly fashion any time it likes, *except* from
> within a signal handler.

Very good, that is what I would expect.

>> There is however a big question here that needs addressing. The term
>> "undefined behavior" is the opposite of defined. You seem to be
>> concerned only that the return value and termination of process threads
>> should be defined. But it is beyond me how you think skipping
>> destructors in general render defined behavior.
>
> *Executing* destructors can cause undefined behavior, because those
> destructors may access a data structure that is in an inconsistent state
> (such as when exit() is called from a signal handler in a
> single-threaded program), or the destructors may deadlock (if exit() is
> called from an arbitrary thread in a threaded program, because the
> destructors may need to acquire locks).

Calling exit() from the signal handler is probably not a good idea. I
would use some mean of notifying the application in the normal flow of
control to shut down. You could send something through a pipe to be
received by a normal application handler, use a flag that is polled, or
use other asynchronous OS service which is safe to use in signal
handlers. Then return from the signal handler. When notified, the
normal application control flow can shut down and return from main, or
possibly call exit().

> Skipping destructors for objects with static storage duration renders
> defined behavior because (as with quick_exit()), the spec would simply
> say that the process disappears and no destructors are called. So
> the code in destructors cannot cause undefined behavior because that
> code never runs.

And since the destructors are not run, and since I have not kept close
accounting on which destructors are skipped and what effect not running
their code have, the end result is undefined to me. If one of those
destructors should have unlocked a lock in a database, or removed a PID
from a lock file, written a summary section to a log file, or .... I
think you get it.

The thing is, I like to program under the assumption that destructors
are run when objects are done, simple as that. Messing with that
assumption is bad unless you really know that it does not matter.

>>> At the cost of more complex APIs, more complex documentation, and
>>> additional learning curve on part of the users of the library. This does
>>> not strike me as good tradeoff.
>>
>> Just try to make sure you do not make it harder than needed by ignoring
>> real issues. The API should be simple, but not too simple. I am a fan
>> of separating the more complex API used by a few specialist users from
>> the common simple API in such a way that the typical user does not have
>> to deal with complex issues unless they have too.
>
> Totally agree with that.

Good.

> But I'm not going to add any complexity
> whatsoever to the Ice API (let alone a whole pile of complex
> machinery to orchestrate shutdown that may be unimplementable on some
> platforms anyway)

Again, I don't expect a solution from the library on things that is not
possible or feasible. But let applications have a try if they want to
try to solve it. Don't tie those application developers up to the
railing of your unsinkable ship. Tell then where they can find the life
rafts.

> just so a process can exit without dumping core or
> deadlocking.

When you use the word *just* here, it sounds like you are the judge of
how important those issues are to applications. It also sounds like you
think that such issues should not be a big deal for anybody. In some
cases it is a big deal, trust me. You are in the danger of excluding
your library from those use-cases or luring users into trouble. If you
do not think your product should be used in those cases, then you should
state so and all would be fine, I think.

> To put this differently: I think it would be wrong for C++ to dictate
> to me how I have to structure my threading, force me to provide
> complex shutdown machinery, or make my library's thread handles
> accessible to the application just so an application can exit.

I agree that the C++ language should not imply such regulations or
restrictions, neither should a good library. Portable language or
library defined behavior is great, but when that is not available then
real engineers look for platform dependent solutions, and that should be
possible.

--
Bjørn

Michi Henning

unread,
Aug 23, 2007, 12:24:25 PM8/23/07
to
Bjørn Roald wrote:

[Sorry for the length of this post. But I felt it necessary to
summarize the problem space more. The summary is that even today's
C++ standard is deficient IMO; when threads enter the picture, things
get worse. I believe that something like quick_exit() is essential
for threaded programs.]

> Calling exit() from the signal handler is probably not a good idea. I
> would use some mean of notifying the application in the normal flow of
> control to shut down. You could send something through a pipe to be
> received by a normal application handler, use a flag that is polled, or
> use other asynchronous OS service which is safe to use in signal
> handlers. Then return from the signal handler. When notified, the
> normal application control flow can shut down and return from main, or
> possibly call exit().

Let me make this a bit clearer. As you say, calling exit() from a signal
handler is most definitely not a good idea because the normal flow of
control is interrupted by the signal and the data structures of the
program can be in any odd state. If the signal handler calls exit(),
global destructors run. A global destructor may need to traverse a
linked list to do its cleanup. However, when the signal arrived,
the program may have been modifying the list, so the lists's pointers
might be all over the place. So, the handler can't call exit().

Even for such a single-threaded program, it is currently not possible
to terminate from within a signal handler other than by calling abort()
or terminate() (which are seen as abnormal exits by the OS). Calling
exit() is not an option, and calling _exit() works in practice, but
has the problem that the standard does not guarantee me that it will
work: on some platform or other, destructors may run anyway and cause
a core dump.

So, leaving threads aside completely, the conclusion I come to is:

A C++ program cannot terminate from within a signal
handler without relying on undefined behavior,
even if that program is single-threaded, if that program needs
control the exit status.

I see that as a shortcoming of the current standard. And I really don't
care what people may feel about the need to execute destructors.
Sometimes, I have a program where I *know* that exiting without running
destructors is perfectly OK, and I should be allowed to exit that
program whenever I feel like it.

Consider the alternatives (again, for a simple single-threaded program).
If the program wants to terminate cleanly upon receipt of a signal, what
is that program supposed to do if it can't exit from within the handler?
The options I see are:

- Set a flag in the handler and periodically poll that flag.

This option is rather ugly because the program may
be CPU-bound and not have any natural place where it could
test the flag, such as when it is in a tight inner loop that
is performance critical.

- I can turn my single-threaded program into a multi-threaded
program and have a second thread listen for the signal and
then somehow initiate termination.

That option is also ugly because it means that I have to
turn a single-threaded program into a multi-threaded program
just so I can terminate upon receipt of a signal. That is a
ridiculous amount of work compared to what it achieves.

Now, with threads, things get worse. As an example, the Ice run time
has all sorts of threads running in the background. They do
blocking and non-blocking I/O, they sleep on condvars, they lock and
unlock mutexes, etc.

Now, suppose the application wants to terminate on receipt of a signal.
So, from the signal handler, the application calls some Ice-provided
function "ice_finish()" or some such. Now, for one, should that
function be blocking on non-blocking? Pragmatically, it cannot be
blocking because there is almost nothing that can safely be called
from a signal handling context: the function simply cannot do it's
job from within the signal handling context.

So, ice_finish() has to be non-blocking. So, how does that work then?
Presumably, the handler would pass a callback function to ice_finish()
that the Ice run time would call to notify the application when shutdown
is complete. But that now means that the application again cannot
terminate from within the handler. Instead, it will have to allow the
handler to return, and then wait for the notification from the Ice
run time. That's pretty much the same thing as setting a flag in
the handler and then polling the flag, except that the polling is
replaced by a callback.

How does the application get the callback? It would obviously be
delivered in a different thread by the Ice run time. So, the application
now becomes multi-threaded, even though it may be inherently single-
threaded. Again, that is a stiff penalty to impose on the application
just so it can go away when a signal arrives. Moreover, what is the
application to do when the callback arrives? It now has to get rid
of its main thread somehow. But that main thread may be CPU-bound
and performance-sensitive, and checking a flag that is set from
the callback may simply not be an option.

Now look at it from the perspective of Ice. How is Ice supposed to
implement ice_finish()? Remember, ice_finish() must able to terminate
an arbitrary number of threads that might be stuck in system calls,
hold locks, might be sleeping on condvars, or night be CPU-bound.
How is the run time supposed to get all these threads to stop? And,
moreover, how is the run time supposed to realize when all
these threads have indeed stopped?

This *cannot* be implemented without thread cancellation because,
without that, there is no way to get a CPU-bound thread to stop running.

But even with thread-cancellation, it is messy, to say the least.
When a thread is cancelled, it may be holding locks, and it may
have data structures in an inconsistent state. So, before terminating,
the thread may need to clean up a whole pile of state so that state is
consistent again. That's necessary because global destructors may
need that state to be consistent. Also, other threads may need that
state to be consistent in order to do *their* clean-up.

So, we have to register thread cancellation handlers that can clean
up each thread's temporarily inconsistent state at any point where
thread cancellation can occur. With dozens of running threads, some
of which are making calls on behalf of the applications because they
call into application functions, that is not only extremely complex,
it is in fact utterly infeasible. The resulting complexity is completely
out of proportion to meeting the need, namely, to terminate on receipt
of a signal.

And we haven't even touched on what thread cancellation means with
respect to destructors of local objects in C++...

So, what you suggest all sounds good except, when you think about the
implications of it on real existing software, it rapidly becomes
infeasible.

>> just so a process can exit without dumping core or
>> deadlocking.
>
> When you use the word *just* here, it sounds like you are the judge of
> how important those issues are to applications.

Generally, I want all my applications to exit without dumping core or
hanging when I hit Ctrl-C. That is an expectation that I believe I
share with the vast majority of users, no matter what field they are
in or what OS they are using.

So, yes, I *just* want to have my application disappear, and disappear
immediately, when I hit Ctrl-C. I believe that is a reasonable and
realistic requirement.

> It also sounds like you
> think that such issues should not be a big deal for anybody. In some
> cases it is a big deal, trust me.

I think as I outlined above, it is indeed a big deal. So big, in fact,
that it is unimplementable without the help of something like
quick_exit().

> You are in the danger of excluding
> your library from those use-cases or luring users into trouble. If you
> do not think your product should be used in those cases, then you should
> state so and all would be fine, I think.

Hmmm... How would you feel about buying a general-purpose middleware
that states up front:

"Any programs written with this library cannot be terminated by a signal
without dumping core on Unix or without popping an ugly window about
abnormal program termination on Windows"?

And that is exactly what happens when I need to terminate from within
a signal handler, because the only available options right now are
abort() and terminate().

The other options are exit(), which results in undefined behavior,
and _exit(), which works for some compilers, but relies on
implementation-dependent behavior and may end up dumping core or
hanging with other compilers.

> I agree that the C++ language should not imply such regulations or
> restrictions, neither should a good library.

Without something like quick_exit(), C++ dictates far more than it has
any right to, IMO.

Cheers,

Michi.


--

Maxim Yegorushkin

unread,
Aug 23, 2007, 12:23:06 PM8/23/07
to
On Aug 6, 6:36 am, Michi Henning <mi...@zeroc.com> wrote:

> I'm in the situation where I need to terminate a threaded program
> from within a signal handler. I cannot call exit() because global
> destructors may find data structures in an inconsistent state
> and crash, or may deadlock on various mutexes. So, I'm calling _exit()
> instead, which (at least for many implementations) prevents global
> destructors from running.
>

> The worrying thing is that the standard doesn't say anything about
> exit() or _exit(), so I'm relying on implementation-dependent behavior.
>

> Calling ::std::terminate() or ::abort() is not an option because
> termination is expected and I want to return zero exit status to
> the OS, but abort() and terminate() both return non-zero exit status
> (and, for some environments, dump core or pop a dialog box about
> abnormal program termination).

Would that not be an option to std::set_terminate() handler to a
function that destroys a process without calling destructors, probably
in a platform specific way, and returns zero exit status? This way the
code could simply call std::terminate().

Can you rely on target platform standards, such as POSIX for the
functionality missing in the C++ standard?

Michi Henning

unread,
Aug 24, 2007, 10:55:03 AM8/24/07
to
Maxim Yegorushkin wrote:
>
> Would that not be an option to std::set_terminate() handler to a
> function that destroys a process without calling destructors, probably
> in a platform specific way, and returns zero exit status? This way the
> code could simply call std::terminate().
>
> Can you rely on target platform standards, such as POSIX for the
> functionality missing in the C++ standard?

No, that doesn't work. Here is the test case:

#include <iostream>
#include <exception>

using namespace ::std;

struct X
{
~X() { cout << "Destroyed an X" << endl; }
};

static X x;

void handler()
{
::exit(0);
}

int main()
{
set_terminate(handler);
terminate();
}

With VS 2005 and gcc 3.4.6, I get:

$ a.out
Destroyed an X
$

With gcc 4.0.3, I get:

$ a.out
terminate called without an active exception
Aborted
$

Obviously, that's not a compliant implementation.

Anyway, what you suggest doesn't work. If my terminate handler calls
exit(), the destructor still runs. And if I call _exit() from the
terminate handler, I end up relying on implementation-dependent
behavior again.

Cheers,

Michi.

0 new messages