For Programmers: Free Programming Magazines  


Home > Archive > ithreads > July 2006 > Thread Exiting









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Thread Exiting
Jerry D. Hedden

2006-07-18, 7:08 pm

Okay, I have the following coded up:

Default behavior is for exit() in main or a thread to exit
the app.

If there are unjoined threads (running or finished),
then a warning is given. (Detached theads are ignored.)

If a thread exits, this warning can be suppressed
with: no warnings 'threads'

If the main thread exits, this warning can't be
suppressed. (Warning is given as part of global
destruction, so warning bits are no longer
available.)

There is a thread-exit-only class method: threads->exit()

If called from main, it acts like 'exit(0)', complete
with warning message as per above, if applicable.

If called in a thread, terminates just the thread
without any warning.

The default behavior for exit() in threads can be changed in
several ways:
Global change
use threads 'exit' => 'threads_only';
# or
use threads 'exit' => 'threads';

At thread creation
threads->create({'exit' => 'thread_only'}, ...);
# or
threads->create({'exit' => 'thread'}, ...);

After thread creation
threads->set_thread_exit_only(); # Inside a thread
# or
$thr->set_thread_exit_only();

When a thread dies, it issues a warning. It the thread's
warning handler subsequently issues an 'exit()', that exit
will operate as per the above.

The exit status (i.e., exit(status)) is preserved and
propogated to the shell.

Comments? Should the exit-override functionality be
scrapped?

Rafael Garcia-Suarez

2006-07-18, 7:08 pm

On 18/07/06, Jerry D. Hedden <jerry@hedden.us> wrote:
> Default behavior is for exit() in main or a thread to exit
> the app.


Which is backwards-compatible, then good.

> There is a thread-exit-only class method: threads->exit()
>
> If called from main, it acts like 'exit(0)', complete
> with warning message as per above, if applicable.


Can't you call threads->exit($status) ?

> The default behavior for exit() in threads can be changed in
> several ways:
> Global change
> use threads 'exit' => 'threads_only';


I assume that's "thread_only".

> # or
> use threads 'exit' => 'threads';


> After thread creation
> threads->set_thread_exit_only(); # Inside a thread
> # or
> $thr->set_thread_exit_only();


Er, set_thread_only_exit($boolean) might be better ?
Mike Pomraning

2006-07-18, 7:08 pm

On Tue, 18 Jul 2006, Rafael Garcia-Suarez wrote:

>
>
> Er, set_thread_only_exit($boolean) might be better ?


How about

$thr->set_attrs( {exit => 'thread_only', foo => 'yes'} );

to allow for arbitrary, individual thread behavior/policy modification
without proliferating methods? Could die() if user attempted to set a
"readonly" ithread attribute (like context, e.g.).

-Mike

Jan Dubois

2006-07-18, 7:08 pm

On Tue, 18 Jul 2006, Jerry D. Hedden wrote:
> Okay, I have the following coded up:
>
> Default behavior is for exit() in main or a thread to exit the app.


[...]

ok

> There is a thread-exit-only class method: threads->exit()


[...]

ok

> The default behavior for exit() in threads can be changed in
> several ways:
> Global change
> use threads 'exit' => 'threads_only';
> # or
> use threads 'exit' => 'threads';


Seems ok, but why do you need both 'threads' and 'threads_only'?

> When a thread dies, it issues a warning. It the thread's warning
> handler subsequently issues an 'exit()', that exit will operate as
> per the above.


This doesn't feel quite right. If exit() terminates the application,
then die() should produce an error and exit the application and not
just produce a warning.

Cheers,
-Jan


Jerry D. Hedden

2006-07-19, 7:07 pm

Jerry D. Hedden wrote:
> When a thread dies, it issues a warning. It the thread's warning
> handler subsequently issues an 'exit()', that exit will operate as
> per the above.


Jan Dubois wrote:
> This doesn't feel quite right. If exit() terminates the application,
> then die() should produce an error and exit the application and not
> just produce a warning.


There seems to be some confusion here. Here's an example of the
behavior I'm talking about.

sub thr_func
{
$SIG{__WARN__} = sub {
print("I hate warnings: $_[0]");
exit(1);
};

die("Thread dies for some reason\n");
}

threads->create('thr_func');
sleep(99);

In the above, the thread 'die's which results in a warning. (In and
of itself, this would not terminate the application.) The warning
is then intercepted by the thread's warning handler which subsequently
executes an 'exit'. This results in the whole application terminating.

Eric Rybski

2006-07-19, 7:07 pm

Jerry,

--- "Jerry D. Hedden" <jerry@hedden.us> wrote:

> The default behavior for exit() in threads can be changed in
> several ways:
> Global change
> use threads 'exit' => 'threads_only';
> # or
> use threads 'exit' => 'threads';
>
> At thread creation
> threads->create({'exit' => 'thread_only'}, ...);
> # or
> threads->create({'exit' => 'thread'}, ...);
>
> After thread creation
> threads->set_thread_exit_only(); # Inside a thread
> # or
> $thr->set_thread_exit_only();
>
> When a thread dies, it issues a warning. It the thread's
> warning handler subsequently issues an 'exit()', that exit
> will operate as per the above.
>
> The exit status (i.e., exit(status)) is preserved and
> propogated to the shell.
>
> Comments? Should the exit-override functionality be
> scrapped?
>
>


What happens to global scope when a module that internally uses threads, like

use threads 'exit' => 'thread';

is dynamically loaded during run-time?

An example script:
use threads;
threads->create({'exit' => 'thread_only'}, sub{
sleep 5;
print "Thread exiting...\n";
exit(0);
});
threads->create(sub{sleep 30;});
require MyModule if int(rand() * 10) >= 5;
$_->join() foreach threads->list;

And the associated module:

package MyModule;
use threads 'exit' => 'thread';

This example indicates that exit() behavior would *dynamically* change for the
script during run-time, depending entirely on whether or not the module were
loaded (a 50/50 chance, in this simple case).

The example script expects thread exit() calls to just exit the current thread,
yet the loaded module enables process exit() for all threads. This would cause
threads started specifically in the script to behave in ways the script author
did not intend, and that behavior is out of his control without having to
modify the module (which may or may not be possible, depending on the software
license or ownership of the module(s), etc.).

Thus, allowing exit() behavior to be changed on a per thread is definately a
good idea; however, allowing exit context changes (via "use") that affect the
entire runtime still seems like a dangerous idea, without constraints.

What if "use threads 'exit' => 'thread';" could be restricted to threads
created within the namespace (i.e. package) of an executed function/method?
And the only exception to this being if use threads 'exit' => 'threads';" were
called in the main:: namespace, exit() would be globally overridden for threads
across ALL packages (no matter how the packages used threads themselves)?

This way, module authors could use it as a nice shortcut; however, end script
writers/application developers could use it to control overall execution
behavior (overriding all loaded module behavior) if desired.

What do you think?

-Eric

Jan Dubois

2006-07-19, 10:11 pm

On Wed, 19 Jul 2006, Jerry D. Hedden wrote:
> In the above, the thread 'die's which results in a warning. (In
> and of itself, this would not terminate the application.) The
> warning is then intercepted by the thread's warning handler which
> subsequently executes an 'exit'. This results in the whole
> application terminating.


I do understand that, it just doesn't feel right to me. A call to
die() should be roughly equivalent to:

sub die {
&{$SIG{__DIE__}}($_[0]) if defined $SIG{__DIE__};
if ($^S) {
$@ = $_[0] || "Died";
# append "at ..." to $@
# throw exception caught by eval block (longjmp)
}
exit($! || ($? >> 8) || 255);
}

I don't understand why you would call the __WARN__ handler instead
of the __DIE__ handler just because this is not the main thread, and
why die() without an eval block would not terminate the application
the same way as a call to exit().

I don't understand the reasoning why die() outside an eval block
should be treated differently from the exit(). You can use all the
same reasoning that it should terminate the application as you can
for the exit() case.

Cheers,
-Jan


Jerry D. Hedden

2006-07-20, 7:06 pm

Eric Rybski asked:
> What if "use threads 'exit' => 'thread';" could be
> restricted to threads created within the namespace (i.e.
> package) of an executed function/method? And the only
> exception to this being if use threads 'exit' =>
> 'threads';" were called in the main:: namespace, exit()
> would be globally overridden for threads across ALL
> packages (no matter how the packages used threads
> themselves)?


I don't know how this would be done. Feel free to take a
crack at implementing such a scheme after I post my changes.
(Although, I don't think it's needed, and question if it's
even a good idea.)

> This way, module authors could use it as a nice shortcut;


Yuck. I'm going to put words in the POD to discourage this.


Jerry D. Hedden

2006-07-20, 7:06 pm

> On Wed, 19 Jul 2006, Jerry D. Hedden wrote:
>
> I do understand that, it just doesn't feel right to me. A call to
> die() should be roughly equivalent to:
>
> sub die {
> &{$SIG{__DIE__}}($_[0]) if defined $SIG{__DIE__};
> if ($^S) {
> $@ = $_[0] || "Died";
> # append "at ..." to $@
> # throw exception caught by eval block (longjmp)
> }
> exit($! || ($? >> 8) || 255);
> }
>
> I don't understand why you would call the __WARN__ handler instead
> of the __DIE__ handler just because this is not the main thread, and
> why die() without an eval block would not terminate the application
> the same way as a call to exit().
>
> I don't understand the reasoning why die() outside an eval block
> should be treated differently from the exit(). You can use all the
> same reasoning that it should terminate the application as you can
> for the exit() case.


Let me be more detailed.

First of all, a thread executes inside an eval via call_sv:
len = (int)call_sv(thread->init_function, thread->gimme|G_EVAL);

Now, if the thread executes a 'die', the 'die' does whatever it
normally does, including executing any die handler, and then the
thread returns from the call_sv.

The XS code then checks on $@ and if set, outputs a warning that
the thread terminated abnormally:
if (SvTRUE(ERRSV) && ckWARN_d(WARN_THREADS)) {
Perl_warn(aTHX_ "Thread %" UVuf " terminated abnormally: %" SVf,
thread->tid, ERRSV);

So far, that's the way it's always been.

Continuing, this warning is issued in the thread's context, so if
the thread has a warn handler, it will get executed.

If that warn handler subsequently executes a 'die', it does
whatever, including executing any die handler, and thread
termination continues, but the application does not terminate.
(This is a change that was agreed upon previous to the current
'exit' discussion. It used to be that the app would terminate at
this point.)

If the warn handler executes an 'exit', that will lead to
application termination. (This is the currently desired behavior
that I am restoring.)


Jan Dubois

2006-07-20, 7:06 pm

On Thu, 20 Jul 2006, Jerry D. Hedden wrote:
>
> Let me be more detailed.
>
> First of all, a thread executes inside an eval via call_sv:
> len = (int)call_sv(thread->init_function, thread->gimme|G_EVAL);
>
> Now, if the thread executes a 'die', the 'die' does whatever it
> normally does, including executing any die handler, and then the
> thread returns from the call_sv.


I understand all this, and I realize that we may need to keep it this
way for backward compatibility. I'm just arguing that the implicit
G_EVAL context for thread functions seems misguided if we think that
exit() should still terminate the application. The user should
set up their own eval block if a fatal die() should be trapped.

Tired mantra: the same arguments as for exit apply.

Anyways, I'm getting a bit tired of discussing this. I support
keeping things as is in the name of backwards compatibility, it
just feels like the original design was not well thought through.

Cheers,
-Jan


Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com