Asuming the following code is running in a seperate Thread:
try{
var stuffToDispose = new SomeClassThatNeedsDisposing();
//doing thing with stuffToDispose
}
finally{
if(stuffToDispose != null)
stuffToDispose.Dispose();
}
and this thread is aborted using the mechanic that raises the ThreadAbortException. Could the ThreadAbortException happen between the null-check and the Dispose()? Aka, in the middle of the finally block?
finally{
if(stuffToDispose != null)
//This is where the Exception would strike
stuffToDispose.Dispose();
}
I am pretty sure the answer is no, but someone else seems convinced it is possible.
In .NET Framework ThreadAbortException is handled in a special way both in catch and finally blocks:
If a ThreadAbortException is caught, it is automatically re-raised at the end of the catch block (unless it is suppressed by Thread.ResetAbort)
In a finally block the ThreadAbortException will not be 'activated' until the end of the whole block. This is an intended behavior. And that's why you can find sometimes obscure codes with and empty try {} block where everything is in the finally section. It guarantees that this section will not be aborted.
On the other hand, .NET Core does not support Thread.Abort (throws a PlatformNotSupportedException). The ThreadAbortException itself has not been removed (for compatibility reasons) so you can still throw it explicitly but I don't think it is still handled as described above (I did not test it).
Finally will not be interrupted if
Running this code under .NET 4.0.0-4.7.2 will lock infinitelly on Thread.Abort() printing foo and hanging in finally:
class Program
{
static void Main(string[] args)
{
var i = false;
var t = new Thread(() =>
{
try { Console.Write("foo"); } finally { while (true) { i=true; } }
});
t.Start();
Thread.Sleep(200);
t.Abort();
t.Join();
Console.WriteLine("bar = {0}", i);
Console.ReadKey();
}
}
Still, there is no guarantee that this will not execute sometimes in further versions.
Finally will be executed but interrupted if
Running same section under .NET 2.0-3.5 will print foobar = True, which implies it is interrupted.
But if you modify it like so:
var t = new Thread(() =>
{
try { Console.Write("foo"); } finally { while (true) { Console.Write(".");} }
});
It will run infinitelly like in first sample. This is ... strange.
Summary
Better to ask it dirrectly at Microsoft.
According to my tests, calling Thread.Abort does not interrupt a currently running finally block inside the thread.
Test code:
var thread = new Thread(() =>
{
try
{
}
catch (ThreadAbortException)
{
Console.WriteLine("ThreadAbortException");
throw;
}
finally
{
Console.WriteLine("Thread Finally Started");
Thread.Sleep(200);
Console.WriteLine("Thread Finally Finished");
}
})
{ IsBackground = true };
thread.Start();
Thread.Sleep(100);
Console.WriteLine("Aborting...");
thread.Abort();
thread.Join();
Output (.NET Framework 4.8):
Thread Finally Started
Aborting...
Thread Finally Finished
Keep in mind that Thread.Abort is not supported on .NET Core.
System.PlatformNotSupportedException: Thread abort is not supported on this platform.
Related
UPDATE: I don't think this question is a duplicate of Can ThreadAbortException skip finally? because (1) I'm not creating another thread, so there's no possibility of a race condition, and (2) this behavior only occurs if the finally block contains an await, which that other question doesn't mention.
Consider this console program:
class Program
{
static void Main()
{
try { T().GetAwaiter().GetResult(); }
catch (ThreadAbortException) { Thread.ResetAbort(); }
catch { }
}
static async Task Abort()
{
//await Task.Delay(1); // A
Thread.CurrentThread.Abort(); // B
}
static async Task T()
{
try
{
await Abort();
}
catch
{
Console.WriteLine("catch");
throw;
}
finally
{
Console.WriteLine("finally");
await Task.Yield(); // C
}
}
}
When I compile this in Visual Studio 2015, the output is
catch
But if I make any one of these changes...
Uncomment line A (and delete the call to Thread.ResetAbort() in Main—another oddity)
Change line B to throw new Exception();
Delete line C
then the output is
catch
finally
Is this behavior a bug, or is it by design (and documented somewhere)?
NOTE: In my actual scenario (an ASP.NET app), the ThreadAbortException is thrown by HttpResponse.Redirect, and I'm performing async I/O in the finally block.
I noticed in System.Threading.TimerBase.Dispose() the method has a try{} finally{} block but the try{} is empty.
Is there any value in using try{} finally{} with an empty try?
http://labs.developerfusion.co.uk/SourceViewer/browse.aspx?assembly=SSCLI&namespace=System.Threading&type=TimerBase
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
internal bool Dispose(WaitHandle notifyObject)
{
bool status = false;
bool bLockTaken = false;
RuntimeHelpers.PrepareConstrainedRegions();
try {
}
finally {
do {
if (Interlocked.CompareExchange(ref m_lock, 1, 0) == 0) {
bLockTaken = true;
try {
status = DeleteTimerNative(notifyObject.SafeWaitHandle);
}
finally {
m_lock = 0;
}
}
Thread.SpinWait(1);
// yield to processor
}
while (!bLockTaken);
GC.SuppressFinalize(this);
}
return status;
}
From http://blog.somecreativity.com/2008/04/10/the-empty-try-block-mystery/:
This methodology guards against a
Thread.Abort call interrupting the
processing. The MSDN page of
Thread.Abort says that “Unexecuted
finally blocks are executed before the
thread is aborted”. So in order to
guarantee that your processing
finishes even if your thread is
aborted in the middle by someone
calling Abort on your thread, you can
place all your code in the finally
block (the alternative is to write
code in the “catch” block to determine
where you were before “try” was
interrupted by Abort and proceed from
there if you want to).
This is to guard against Thread.Abort interrupting a process. Documentation for this method says that:
Unexecuted finally blocks are executed before the thread is aborted.
This is because in order to recover successfully from an error, your code will need to clean up after itself. Since C# doesn't have C++-style destructors, finally and using blocks are the only reliable way of ensuring that such cleanup is performed reliably. Remember that using block turns into this by the compiler:
try {
...
}
finally {
if(obj != null)
((IDisposable)obj).Dispose();
}
In .NET 1.x, there was a chance that finally block will get aborted. This behavior was changed in .NET 2.0.
Moreover, empty try blocks never get optimized away by the compiler.
The following code seems as though it should swallow any type of exception in the try block, but the IIS worker process periodically dies and restarts because of an unhandled exception (marked with a comment.)
try
{
while (true)
{
DispatcherTask task = null;
lock (sync)
{
task = this.getTask();
if (task == null)
{
Monitor.Wait(sync);
continue;
}
}
lock (task)
{
task.Result = task.Task.DynamicInvoke(task.Params);
// ^ Delegate.DynamicInvoke(object[]) throws a TargetInvocationException
Monitor.PulseAll(task);
}
}
}
catch (Exception e)
{
}
UPDATE:
Definition of DispatcherTask:
private class DispatcherTask
{
public Delegate Task;
public object[] Params;
public object Result;
}
You cannot catch the exceptions of another thread, at least not in this way. Catch your exception inside the newly opened thread and you will be fine.
In .NET 4 and up, AccessViolationException will bypass catch blocks by default. Catching of such exceptions can be enabled in web.config, but should not be, as they typically result from errors in unmanaged code and signal that the application state is corrupted.
I encountered a scenario where ReaderWriterLockSlim seems to get broken after a series of legal actions.
The flow is:
Thread 1 takes writer lock1
Thread 2 tries to take reader lock1 - blocks
Thread 2 is interrupted, and calls lock1.ExitReadLock
Thread 2 didn't get the lock. It seems that an exception should have been thrown.
Thread 1 exits writer lock of lock1
Any thread that tries to take lock1.EnterReadLock will block forever
After stage 3 above, a debugger shows that lock1.CurrentReadCount is corrupt - seems to have overflowed down to 0x7FFFFFF.
I wonder if anyone had encountered this, or maybe I'm missing something.
The code that reproduces it:
[TestMethod]
public void ReproTest()
{
var rwlock = new ReaderWriterLockSlim();
rwlock.EnterWriteLock();
bool taken = false;
var reader = new Thread(() =>
{
try
{
rwlock.EnterReadLock();
s_logger.Info("Enter");
}
catch (ThreadInterruptedException)
{
rwlock.ExitReadLock();
}
});
reader.Name = "Reader";
reader.Start();
Thread.Sleep(1000);
reader.Interrupt();
Thread.Sleep(1000);
rwlock.ExitWriteLock();
while (!taken)
{
taken = rwlock.TryEnterReadLock(1000);
}
Thread.Sleep(1000);
}
This looks like a bug in the framework (tested on v3.5 and v4.0). The ExitReadLock() should throw a SynchronizationLockException, but doesn't in this case. Indeed, you can trigger a very similar issue much more simply with the following:
rwlock.EnterReadLock();
rwlock.ExitReadLock();
// This should throw a SynchronizationLockException but doesn't
rwlock.ExitReadLock();
// At this point, rwlock.CurrentReaderCount = 0x0fffffff
(In fact, ExitReadLock() will corrupt the lock if it's called without a matching EnterReadLock() on any thread that has previously entered the lock.)
The issue only occurs when the ReaderWriterLockSlim is created using the parameterless constructor, or with LockRecursionPolicy.NoRecursion. If created with LockRecursionPolicy.SupportsRecursion, it will not be corrupted by the unmatched ExitReadLock().
If you expect the reader thread to be interrupted whilst waiting for entry into lock, I would suggest changing the reader thread method to:
var reader = new Thread(() =>
{
var entered = false;
try
{
rwlock.EnterReadLock();
entered = true;
s_logger.Info("Enter");
}
finally
{
if (entered) rwlock.ExitReadLock();
}
});
The reader is never entering the read lock. It sits waiting for the write to be released. When it's interrupted, you then try to exit even though you never entered, causing read count to go below 0 I suppose :)
Code that fixes what #Lasse and #Jeremy have pointed out:
static public void ReproTest()
{
var rwlock = new ReaderWriterLockSlim();
rwlock.EnterWriteLock();
s_logger.Info("0:Enter");
bool taken1 = false;
var reader = new Thread(() =>
{
try
{
rwlock.EnterReadLock();
s_logger.Info("1:Enter");
// only set to true if taken
taken1 = true;
}
catch (ThreadInterruptedException)
{
// only release if taken
if (taken1)
rwlock.ExitReadLock();
taken1 = false;
}
});
reader.Name = "Reader";
reader.Start();
Thread.Sleep(1000);
reader.Interrupt();
Thread.Sleep(1000);
rwlock.ExitWriteLock();
// 2nd taken variable here only so we can see state of taken1
bool taken2 = taken1;
while (!taken2)
{
taken2 = rwlock.TryEnterReadLock(1000);
s_logger.Info("2:Enter");
}
Thread.Sleep(1000);
}
When run, the debug output correctly shows the write lock being taken, the 1st read lock NOT taken, and the 2nd read lock taken:
0:Enter
A first chance exception of type 'System.Threading.ThreadInterruptedException' occurred in mscorlib.dll
The thread 'Reader' (0x1358) has exited with code 0 (0x0).
2:Enter
I have another question about this same code and keeping the pipe open after the client closes it
But here i have a problem gracefully terminating my app. My main code is below. There are 2 problems. 1) I am using Thread.Abort and 2) This application doesnt actually end. I can set a breakpoint and see abort is called and step to the ending brace but the IDE is still in debug mode and the process is still alive (in process manager). How do i properly terminate this?
[STAThread]
static void Main(string[] args)
{
Thread t;
t = new Thread(new ThreadStart(ThreadStartServer));
bool hasInstance = true;
try
{
pipeStream = new NamedPipeServerStream(pipename);
hasInstance = false;
pipeStream.Close();
t.Start();
pipeStream.Dispose();
}
catch (System.IO.IOException)
{
hasInstance = true;
}
if (hasInstance)
{
clientPipeMessage(args[1]);
return;
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
t.Abort();
}
static public void ThreadStartServer()
{
while (true)
{
using (NamedPipeServerStream pipeStream = new NamedPipeServerStream(pipename))
{
Console.WriteLine("[Server] Pipe created {0}", pipeStream.GetHashCode());
// Wait for a connection
pipeStream.WaitForConnection();
Console.WriteLine("[Server] Pipe connection established");
using (StreamReader sr = new StreamReader(pipeStream))
{
string temp;
while ((temp = sr.ReadLine()) != null)
{
Console.WriteLine("{0}: {1}", DateTime.Now, temp);
}
}
}
}
Console.WriteLine("Connection lost");
}
About Thread.Abort from MS documentation ... "Calling this method usually terminates the thread."
Furthermore "The thread is not guaranteed to abort immediately, or at all."
I suspect the WaitForConnection is blocking it from receiving the thread abort. Generally speaking, thread abort is considered Evil as who knows what state you could leave things in, etc. See here for some more help...http://www.interact-sw.co.uk/iangblog/2004/11/12/cancellation
As you suggest ... don't use Thread.Abort. Unless you have a very compelling reason why no other option will work it is a bad idea.
The problem is the blocking call to ReadLine ... so instead use StreamReader.Peek/Read to pull data from the named pipe. This will allow you to check a flag in the loop so that you can exit.
For a more complex solution you could use asynchronous I/O ... see this question for some pointers.
You need to "return" from your ThreadStartServer method when it has completed its work. If you combine this with a Join() in the Main method, the worker thread will finish gracefully. Additionally make it a BackGround thread. Here is an example (without the PipeStream):
class Prog
{
static void Main(string[] args)
{
Thread t;
t = new Thread(new ThreadStart(ThreadStartServer));
t.IsBackground = true;
try
{
t.Start();
// time consuming work here
}
catch (System.IO.IOException)
{
// from your example
}
t.Join();
}
static public void ThreadStartServer()
{
while (true)
{
int counter=0;
while (++counter < 10)
{
Console.WriteLine("working.");
// do time consuming things
Thread.Sleep(500);
}
return;
}
}
}