Interruption and interruption of flows should be avoided, as this can lead to damage to the state of the running program. For example, imagine that you interrupted a thread that held locks on resources, these locks will never be released.
Instead, consider using a signaling mechanism so that threads can interact with each other and therefore correctly lock and unlock the descriptor, for example:
private readonly AutoResetEvent ProcessEvent = new AutoResetEvent(false); private readonly AutoResetEvent WakeEvent = new AutoResetEvent(false); public void Do() { Thread th1 = new Thread(ProcessSomething); th1.IsBackground = false; th1.Start(); ProcessEvent.WaitOne(); Console.WriteLine("Processing started..."); Thread th2 = new Thread(() => WakeEvent.Set()); th2.Start(); th1.Join(); Console.WriteLine("Joined"); } private void ProcessSomething() { try { Console.WriteLine("Processing..."); ProcessEvent.Set(); } finally { WakeEvent.WaitOne(); Console.WriteLine("Woken up..."); } }
Update
Pretty interesting low level problem. Although Abort() documented, Interrupt() much smaller.
The short answer to your question is no, you cannot wake a stream in a finally block by calling it Abort or Interrupt .
The inability to interrupt or interrupt flows in finally blocks by design, just so that ultimately the blocks can run as you expected. If you could interrupt and interrupt threads in finally blocks, this could lead to unforeseen consequences for cleaning procedures, and therefore leaving the application in a damaged state is not good.
A small nuance with thread interruption is that the interrupt may have been thrown against the thread at any time before it entered the finally block, but so far it has not been in the SleepWaitJoin state (i.e. not blocked). In this case, if there was a blocking call in the finally block, it immediately threw a ThreadInterruptedException and broke out of the finally block. Finally, block protection prevents this.
In addition to protection in finally blocks, this extends to try blocks, as well as to CER ( Constrained Execution Region ), which can be configured in user code to prevent the exclusion of a number of exceptions until a region is executed - very useful for critical code blocks to be completed, and delay interruptions.
An exception (no pun intended ) is what is called Rude Aborts . These are ThreadAbortExceptions created by the CLR hosting environment. This can lead to the fact that the final and blocking blocks will be displayed, but not CERs. For example, the CLR may call Rude Aborts in response to threads that, in its opinion, are too long to complete their work / exit, for example. while trying to unload AppDomain or execute code in SQL Server CLR. In your specific example, when your application shuts down and the AppDomain is unloaded, the CLR will issue Rude Abort in a sleep thread, as there will be a waiting time for the AppDomain to unload.
Undoing and interrupting in finally blocks will not happen in the user code, but there is a slightly different behavior between the two cases.
Abort
When Abort called in a thread in a finally block, the calling thread is blocked. This is documented :
The thread that calls Abort can block if the thread that is interrupted is in a protected area of ββcode, such as a catch block, finally block, or a limited execution area.
In case of interruption, if the dream was not endless:
- The calling thread throws
Abort , but blocks it until the finally block is completed, i.e. it stops here and does not immediately jump to the Join statement. - The called party stream is set to
AbortRequested . - The caller continues to sleep.
- When the called call wakes up, since it has the
AbortRequested state, it will continue to execute the code of the finally block and then "evaporate", that is, it will exit. - When the interrupted thread leaves the finally block: an exception does not occur, after the completion of the finally block, the code is absent, and the state of the
Aborted thread. - The calling thread unlocks, continues the
Join statement, and immediately jumps to how the called thread is called.
Therefore, given your endless sleep example, the calling thread will block forever in step 1.
Interrupt
In case of interruption, if the dream was not endless:
Not so well documented ...
- The calling thread will issue
Interrupt and continue execution. - The calling thread will block the
Join statement. - The callee thread has its own status set to raise an exception on the next blocking call, but, anyway, it is in the finally block, it is not unlocked, that is, woken.
- The caller continues to sleep.
- When waking up, it will continue to execute the finally block.
- When an interrupted thread leaves the finally block, it throws a
ThreadInterruptedException in its next blocking call (see the code example below). - The calling thread "joins" and continues as it
ThreadInterruptedException called thread, however, an unhandled ThreadInterruptedException in step 6 has now smoothed the process ...
So, again, your example with endless sleep, the calling thread will be blocked forever, but in step 2.
Summary
So, although Abort and Interrupt have a slightly different behavior, they will cause the called thread to sleep forever and the calling thread to block forever (in your example).
Only Rude Abort can make a blocked thread exit the finally block, and they can only be raised by the CLR itself (you cannot even use reflection for diddle ThreadAbortException.ExceptionState , since it makes an internal CLR call to get AbortReason - there is no way to be easily evil there. ..).
The CLR prevents the premature failure of code blocks for our own good - it helps prevent a damaged state.
An example of a slightly different behavior with Interrupt :
internal class ThreadInterruptFinally { public static void Do() { Thread t = new Thread(ProcessSomething) { IsBackground = false }; t.Start(); Thread.Sleep(500); t.Interrupt(); t.Join(); } private static void ProcessSomething() { try { Console.WriteLine("processing"); } finally { Thread.Sleep(2 * 1000); } Console.WriteLine("Exited finally..."); Thread.Sleep(0);