Finally not being called in a thread

L

Lee Alexander

I wrote some code in a method called in a separate thread via the ThreadPool
where I expected my code in a Finally section to be called but it never did.
I'd be interested to know why this is the case? Here's some code to repro
the behaviour:

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication7
{
class Program
{
static void DoSomething( object state )
{
try
{
int count = 0;
while( true )
{
Console.WriteLine( count++ );
System.Threading.Thread.Sleep( 500 );
}
}
finally
{
Console.WriteLine( "Thread Finished" );
}
}
static void Main( string[] args )
{
System.Threading.ThreadPool.QueueUserWorkItem( new
System.Threading.WaitCallback( DoSomething ) );
System.Threading.Thread.Sleep( 5000 );
System.Console.WriteLine( "Process Done" );
}
}
}

Regards

Lee Alexander
www.feedghost.com
An RSS Reader for Vista & XP
Synchronize, search, tag and share.
 
M

Marc Gravell

while(true) will never exit...

even if you were hoping for an int overflow (that won't happen) it
would take, what, 34 years?

Marc
 
M

Marc Gravell

For completeness - your app is exiting (without calling the finally)
because the pool thread is a *background* thread, and therefore
doesn't keep the exe alive. When the last foreground thread exits, the
process dies. Finally does not get respected if the process is ripped
down.

Marc
 
J

Jon Skeet [C# MVP]

while(true) will never exit...

even if you were hoping for an int overflow (that won't happen) it
would take, what, 34 years?

My guess is that the OP was hoping that the application exiting would
effectively trigger a Thread.Abort in all background threads, which
would indeed cause the finally block to execute. Looks like this isn't
the case (or at least isn't always the case), despite what
http://www.devsource.com/article2/0,1895,1952643,00.asp says.

Jon
 
C

Christof Nordiek

Jon Skeet said:
My guess is that the OP was hoping that the application exiting would
effectively trigger a Thread.Abort in all background threads, which
would indeed cause the finally block to execute. Looks like this isn't
the case (or at least isn't always the case), despite what
http://www.devsource.com/article2/0,1895,1952643,00.asp says.

Jon
From this link:
http://msdn2.microsoft.com/en-us/library/h339syd0(vs.80).aspx
shutting down does not throw an AbortException in backgrpund threads.

Christof
 
L

Lee Alexander

Marc,

This wasn't the issue (just example code), I was just trying to show that
finally never got called. Sorry if I didn't explain myself properly...

Anyway thanks for replying

Regards
Lee
 
G

Guest

To a certain extent the documenation assumes you know a couple of things:
Exiting an application while a background thread is running is effectively
the same as calling Thread.Terminate on that thread. Whenever a thread is
terminated it simply stops running, meaning no unreached finally blocks will
be called, which also means existing locks with the "lock" statement won't
get unlocked, IDisposable objects used with "using" won't get disposed etc.

It's the same when you use Program Manager to terminate an application; if
the application does not response to a WM_CLOSE message it will simply stop
running: no unreached finally blocks will be called and no garbage collection
will occur.

Another issue with terminating a thread either explicitly or implicitly is
if that thread is in the constructor for an object. In that case you can no
longer create objects of that type because the c'tor locks the class, if it
doesn't exit properly it won't unlock the class. This is the primary reason
why Thread.Terminate and Thread.Pause were made obsolete.
--
Browse http://connect.microsoft.com/VisualStudio/feedback/ and vote.
http://www.peterRitchie.com/blog/
Microsoft MVP, Visual Developer - Visual C#


Lee Alexander said:
Thanks guys, I guess in the documentation it would be nice to mention that
the try / finally clause is not honoured in this scenario, just to be
explicit:

http://msdn2.microsoft.com/en-us/library/h339syd0(vs.80).aspx


Anyway thanks again for taking time to look into this for me..

Regards
Lee

Lee Alexander said:
I wrote some code in a method called in a separate thread via the
ThreadPool where I expected my code in a Finally section to be called but
it never did. I'd be interested to know why this is the case? Here's some
code to repro the behaviour:

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication7
{
class Program
{
static void DoSomething( object state )
{
try
{
int count = 0;
while( true )
{
Console.WriteLine( count++ );
System.Threading.Thread.Sleep( 500 );
}
}
finally
{
Console.WriteLine( "Thread Finished" );
}
}
static void Main( string[] args )
{
System.Threading.ThreadPool.QueueUserWorkItem( new
System.Threading.WaitCallback( DoSomething ) );
System.Threading.Thread.Sleep( 5000 );
System.Console.WriteLine( "Process Done" );
}
}
}

Regards

Lee Alexander
www.feedghost.com
An RSS Reader for Vista & XP
Synchronize, search, tag and share.
 
J

Jon Skeet [C# MVP]

On Jun 29, 2:44 pm, Peter Ritchie [C# MVP] <[email protected]>
wrote:
Another issue with terminating a thread either explicitly or implicitly is
if that thread is in the constructor for an object. In that case you can no
longer create objects of that type because the c'tor locks the class, if it
doesn't exit properly it won't unlock the class. This is the primary reason
why Thread.Terminate and Thread.Pause were made obsolete.

Gosh, I wasn't aware of that. Any idea *why* it does that? Also, if
that's the case, why does the following code appear to be running
multiple threads within a constructor?

using System;
using System.Threading;

class Test
{

public Test(int number)
{
for (int i=0; i < 1000; i++)
{
Console.WriteLine ("Constructor {0}: {1}", number, i);
Thread.Sleep(500);
}
}

static void Main()
{
for (int i=0; i < 5; i++)
{
new Thread (Count).Start(i);
}
}

static void Count(object state)
{
new Test((int)state);
}
}

I don't suppose you meant the *static* constructor, did you? That
would certainly make sense (and be much less of a risk).

Jon
 
W

Willy Denoyette [MVP]

Peter Ritchie said:
To a certain extent the documenation assumes you know a couple of things:
Exiting an application while a background thread is running is effectively
the same as calling Thread.Terminate on that thread. Whenever a thread is
terminated it simply stops running, meaning no unreached finally blocks
will
be called, which also means existing locks with the "lock" statement won't
get unlocked, IDisposable objects used with "using" won't get disposed
etc.

It's the same when you use Program Manager to terminate an application; if
the application does not response to a WM_CLOSE message it will simply
stop
running: no unreached finally blocks will be called and no garbage
collection
will occur.

Another issue with terminating a thread either explicitly or implicitly is
if that thread is in the constructor for an object. In that case you can
no
longer create objects of that type because the c'tor locks the class, if
it
doesn't exit properly it won't unlock the class. This is the primary
reason
why Thread.Terminate and Thread.Pause were made obsolete.
--

Aren't you confusing Thread.Resume and Thread.Suspend with Pause and
Terminate? I have never seen Thread.Terminate and Thread.Pause in the FCL
In the OP's case, the CLR performs an orderly shutdown prior to the call to
ExitProcess, an orderly shutdown gives your managed code a chance to
participate in the shutdown process.

Willy.
 
G

Guest

Actually yes, that should be static constructors and synchronized methods.
--
Browse http://connect.microsoft.com/VisualStudio/feedback/ and vote.
http://www.peterRitchie.com/blog/
Microsoft MVP, Visual Developer - Visual C#


Jon Skeet said:
On Jun 29, 2:44 pm, Peter Ritchie [C# MVP] <[email protected]>
wrote:
Another issue with terminating a thread either explicitly or implicitly is
if that thread is in the constructor for an object. In that case you can no
longer create objects of that type because the c'tor locks the class, if it
doesn't exit properly it won't unlock the class. This is the primary reason
why Thread.Terminate and Thread.Pause were made obsolete.

Gosh, I wasn't aware of that. Any idea *why* it does that? Also, if
that's the case, why does the following code appear to be running
multiple threads within a constructor?

using System;
using System.Threading;

class Test
{

public Test(int number)
{
for (int i=0; i < 1000; i++)
{
Console.WriteLine ("Constructor {0}: {1}", number, i);
Thread.Sleep(500);
}
}

static void Main()
{
for (int i=0; i < 5; i++)
{
new Thread (Count).Start(i);
}
}

static void Count(object state)
{
new Test((int)state);
}
}

I don't suppose you meant the *static* constructor, did you? That
would certainly make sense (and be much less of a risk).

Jon
 
G

Guest

Willy Denoyette said:
In the OP's case, the CLR performs an orderly shutdown prior to the call to
ExitProcess, an orderly shutdown gives your managed code a chance to
participate in the shutdown process.

I'm not sure what "orderly shutdown" the OP's DoSomething method can
particpate in when the application exits. The thread that DoSomething is
running on does not have it's Abort method called, so DoSomething can't catch
ThreadAbortException.
 
W

Willy Denoyette [MVP]

Peter Ritchie said:
I'm not sure what "orderly shutdown" the OP's DoSomething method can
particpate in when the application exits. The thread that DoSomething is
running on does not have it's Abort method called, so DoSomething can't
catch
ThreadAbortException.


This has nothing to do with ThreadAbortException, In the OP's case (running
a console program!), the CLR starts an "orderly shutdown" after "Main"
returns, this implies raising the "ProcessExit" event, a ProcessExit event
handler can for instance be used (amongst other things) to coordinate an
orderly shutdown of the thread running DoSomething (see [1] for a sample),
note that the handler is constrained by a time-out of 3 seconds.
After the ProcessExit handler returns, it's no longer possible to run (nor
start) any managed activity other than what is done in your finalizers
(destructors in C"). The finalizers are also constrained by time-out value
of max. 2 secs. per finalizer.

Above does not happen when you end a "managed" process, nor when you stop
the parent shell of the console process from taskman. In both cases, the OS
will stop scheduling any of the process threads and remove the process cold.

Willy.

[1]
class Program
{
static bool done;
static void DoSomething( object state )
{
try
{
int count = 0;
while( !done )
{
Console.WriteLine( count++ );
System.Threading.Thread.Sleep(200);
}
}
finally
{
Console.WriteLine( "Thread Finished" );
}
}
static void Main( string[] args )
{
AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit;

System.Threading.ThreadPool.QueueUserWorkItem( new
System.Threading.WaitCallback( DoSomething ) );
System.Threading.Thread.Sleep(1000);
System.Console.WriteLine( "Main Done" );
}
public static void CurrentDomain_ProcessExit(object sender, EventArgs e)
{
AppDomain domain = sender as AppDomain;
Console.WriteLine("... ending domain is: " + domain.FriendlyName);
Console.WriteLine("Clean-up global stuff...");
done = true;
Thread.Sleep(500); // give thread some extra time to finish
}
}
 
P

Peter Ritchie [C#MVP]

I think re-writing/changing the DoSomething method went without saying.
ProcessExit really has nothing to do with the OPs case since after making
modifications like that to DoSomething he could just set done to true and
Sleep at the end of Main.

The question wasn't "What do I need to do to make sure my finally block is
called", it was "...I expected the code in a finally section to be called
but it never did" to which I was supplying a couple more examples why it
isn't guaranteed to be called. Obviously, if you ask a thread to terminate,
you're no longer in any of those cases.

Alternatively, the finally block in DoSomething could get called without
modification if ProcessExit called Thread.Abort on the thread, but I always
recommend asking infinite threads to exit rather than using exceptions for
non-exceptional logic.

-- Peter


Willy Denoyette said:
Peter Ritchie said:
I'm not sure what "orderly shutdown" the OP's DoSomething method can
particpate in when the application exits. The thread that DoSomething is
running on does not have it's Abort method called, so DoSomething can't
catch
ThreadAbortException.


This has nothing to do with ThreadAbortException, In the OP's case
(running a console program!), the CLR starts an "orderly shutdown" after
"Main" returns, this implies raising the "ProcessExit" event, a
ProcessExit event handler can for instance be used (amongst other things)
to coordinate an orderly shutdown of the thread running DoSomething (see
[1] for a sample), note that the handler is constrained by a time-out of 3
seconds.
After the ProcessExit handler returns, it's no longer possible to run (nor
start) any managed activity other than what is done in your finalizers
(destructors in C"). The finalizers are also constrained by time-out value
of max. 2 secs. per finalizer.

Above does not happen when you end a "managed" process, nor when you stop
the parent shell of the console process from taskman. In both cases, the
OS will stop scheduling any of the process threads and remove the process
cold.

Willy.

[1]
class Program
{
static bool done;
static void DoSomething( object state )
{
try
{
int count = 0;
while( !done )
{
Console.WriteLine( count++ );
System.Threading.Thread.Sleep(200);
}
}
finally
{
Console.WriteLine( "Thread Finished" );
}
}
static void Main( string[] args )
{
AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit;

System.Threading.ThreadPool.QueueUserWorkItem( new
System.Threading.WaitCallback( DoSomething ) );
System.Threading.Thread.Sleep(1000);
System.Console.WriteLine( "Main Done" );
}
public static void CurrentDomain_ProcessExit(object sender, EventArgs e)
{
AppDomain domain = sender as AppDomain;
Console.WriteLine("... ending domain is: " + domain.FriendlyName);
Console.WriteLine("Clean-up global stuff...");
done = true;
Thread.Sleep(500); // give thread some extra time to finish
}
}
 
W

Willy Denoyette [MVP]

Peter Ritchie said:
I think re-writing/changing the DoSomething method went without saying.
ProcessExit really has nothing to do with the OPs case since after making
modifications like that to DoSomething he could just set done to true and
Sleep at the end of Main.

The question wasn't "What do I need to do to make sure my finally block is
called", it was "...I expected the code in a finally section to be called
but it never did" to which I was supplying a couple more examples why it
isn't guaranteed to be called. Obviously, if you ask a thread to
terminate, you're no longer in any of those cases.

Alternatively, the finally block in DoSomething could get called without
modification if ProcessExit called Thread.Abort on the thread, but I
always recommend asking infinite threads to exit rather than using
exceptions for non-exceptional logic.

You asked - I'm not sure what "orderly shutdown" the OP's DoSomething method
can participate in when the application exits.- and I showed you how one can
participate in an orderly shutdown if you need to, so I your question,
right?
Sure, I could have called Thread.Abort, but I don't like to promote this
API, although, in this case, it would not cause much harm.
Anyway, this is not exactly my point, an "orderly shutdown" is started when
"Main" returns, the GC kicks in, the finalizers are run (non guaranteed) and
you can participate in the "shutdown" if you need to, this is what I call
the OP's case. Nothing of this all happens when you initiate a "rude
shutdown" , that is, end a console program or a windows program that does
not respond to WM_CLOSE from taskman. Here, you effectively kill the process
by means of a "TerminateProcess" call, no threads are killed no single piece
of process code is run, the process is just removed from the system.

Willy.
 
P

Peter Ritchie [C#MVP]

You asked - I'm not sure what "orderly shutdown" the OP's DoSomething
method can participate in when the application exits.- and I showed you
how one can participate in an orderly shutdown if you need to, so I your
question, right?
Sure, I could have called Thread.Abort, but I don't like to promote this
API, although, in this case, it would not cause much harm.
Anyway, this is not exactly my point, an "orderly shutdown" is started
when "Main" returns, the GC kicks in, the finalizers are run (non
guaranteed) and you can participate in the "shutdown" if you need to, this
is what I call the OP's case.

I guess I'm reading too much into "orderly shutdown". I wasn't associating
it with the opposite of a rude shutdown and that you were suggesting the
framework would do something to get the thread into the finally block
without modification of DoSomething method.

<snip>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top