Why does deadlock occur on calling Semaphore.WaitOne? - c#

The run() function in the following code is called from other threads simultaneously. At anytime, on any line, a ThreadAbortException might occur according to the general design of the application, which I cannot change.
I sometimes get SemaphoreFullException while calling pool.Release(). I think this occurs if a thread abort exception occurs while calling "pool.WaitOne()". During my debug tries, after SemaphoreFullException has occurred, there is no problem in running the code. After that exception, pool.WaitOne() calls and other things work just as expected.
I haven't been able to get a deadlock situation during my local debug sessions. However, in a remote computer, I have a deadlock with this code. I attach that process using remote debugger and see that the execution is locked on the line pool.WaitOne();.
I can't figure out how this would happen, and what I'm doing wrong. Any help is very appreciated.
private static object poolLocker = new object();
private static Semaphore _pool;
private static Semaphore pool
{
get
{
if (_pool == null)
lock (poolLocker)
if (_pool == null)
{
int count = myMaximumThreadCount;
_pool = new Semaphore(count, count);
}
return _pool;
}
}
private void run()
{
try
{
pool.WaitOne();
do_something_that_may_throw_exception();
}
finally
{
try
{
pool.Release();
}
catch (SemaphoreFullException) { }
}
}

Try to change the initialization of the semaphore object in pool property to:
private static Semaphore pool
{
get
{
if (_pool == null)
lock (poolLocker)
if (_pool == null)
{
int count = myMaximumThreadCount;
_pool = new Semaphore(0, count);
}
return _pool;
}
}
An initial count for this semaphore should be set to zero.

I have found the cause of the deadlock; and it has nothing to do with the question I've asked, so this is a bad question, sorry for that. There seems to be no problem in the code in the question.
The cause: In the do_something_that_may_throw_exception() function, an extern function of a C++ library is being called. When an error occurs in the C++ function, a SEHException is thrown. However, in my tries this exception can only be caught in a function that has HandleProcessCorruptedStateExceptions and SecurityCritical attributes. And that function happens to call the run() function of the question. However, the finally part of the run() function is newer executed! Also, if you have a using(IDisposable object){ ... } and the SEHException occurs inside it; object's Dispose() function won't be called.
I've used the following function for calling the C++ function; and everything worked fine:
SafeCall(()=> call_external_cpp_function());
[HandleProcessCorruptedStateExceptions]
[SecurityCritical]
internal static void SafeCall(Action action)
{
try
{
action();
}
catch (System.Threading.ThreadAbortException) { throw; }
catch (System.Threading.ThreadInterruptedException) { throw; }
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}

Related

Gracefully handling corrupted state exceptions

Related to this question, I would like to force CLR to let my .NET 4.5.2 app catch Corrupted State Exceptions, for the sole purpose of logging them and then terminating the application. What's the correct way to do this, if I have catch (Exception ex) at several places around the app?
So, after I specify the <legacyCorruptedStateExceptionsPolicy> attribute, if I understood correctly, all the catch (Exception ex) handlers will catch exceptions like AccessViolationException and happily continue.
Yeah, I know catch (Exception ex) is a Bad Idea™, but if CLR would at least put the correct stack trace into the Event Log, I would be more than happy to explain to the customer that his server app failing fast at 1AM and being offline for the night is a good thing. But unfortunately, CLR logs an unrelated exception into the Event Log and then closes the process so that I cannot find out what actually happened.
The question is, how to make this happen, process wide:
if the exception thrown is a Corrupted State Exception:
- write the message to the log file
- end the process
(Update)
In other words, this would probably work for most exceptions in a simple app:
[HandleProcessCorruptedStateExceptions]
[SecurityCritical]
static void Main() // main entry point
{
try
{
}
catch (Exception ex)
{
// this will catch CSEs
}
}
But, it won't work for:
Unhandled app domain exceptions (i.e. thrown on non-foreground threads)
Windows Service apps (which don't have an actual Main entry point)
So it seems like <legacyCorruptedStateExceptionsPolicy> is the only way to make this work, in which case I don't know how to fail after logging the CSE?
Instead of using <legacyCorruptedStateExceptionsPolicy> it would be better to use [HandleProcessCorruptedStateExceptions] (and [SecurityCritical]) as stated here:
https://msdn.microsoft.com/en-us/magazine/dd419661.aspx
Following that, your Main method should look something like this:
[HandleProcessCorruptedStateExceptions, SecurityCritical]
static void Main(string[] args)
{
try
{
...
}
catch (Exception ex)
{
// Log the CSE.
}
}
But be aware that this doesn't catch the more serious exceptions like StackOverflowException and ExecutionEngineException.
Also finally of involved try blocks will not be executed:
https://csharp.2000things.com/2013/08/30/920-a-finally-block-is-not-executed-when-a-corrupted-state-exception-occurs/
For other unhandled appdomain exceptions you can use :
AppDomain.CurrentDomain.UnhandledException
Application.Current.DispatcherUnhandledException
TaskScheduler.UnobservedTaskException
(Please do a search for the details when a specific handler is appropriate for your situation. TaskScheduler.UnobservedTaskException for example is a bit tricky.)
If you don't have access to the Main method, you can also mark your AppDomain exception handler to catch the CSE:
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
...
[HandleProcessCorruptedStateExceptions, SecurityCritical]
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
// AccessViolationExceptions will get caught here but you cannot stop
// the termination of the process if e.IsTerminating is true.
}
The last line of defense could be an unmanaged UnhandledExceptionFilter like this:
[DllImport("kernel32"), SuppressUnmanagedCodeSecurity]
private static extern int SetUnhandledExceptionFilter(Callback cb);
// This has to be an own non generic delegate because generic delegates cannot be marshalled to unmanaged code.
private delegate uint Callback(IntPtr ptrToExceptionInfo);
And then somewhere at the beginning of your process:
SetUnhandledExceptionFilter(ptrToExceptionInfo =>
{
var errorCode = "0x" + Marshal.GetExceptionCode().ToString("x2");
...
return 1;
});
You can find more information about the possible return codes here:
https://msdn.microsoft.com/en-us/library/ms680634(VS.85).aspx
A "specialty" of the UnhandledExceptionFilter is that it isn't called if a debugger is attached. (At least not in my case of having a WPF app.) So be aware of that.
If you set all the appropriate ExceptionHandlers from above, you should be logging all exceptions that can be logged. For the more serious exceptions (like StackOverflowException and ExecutionEngineException) you have to find another way because the whole process is unusable after they happened. A possible way could perhaps be another process that watches the main process and logs any fatal errors.
Additional hints:
In the AppDomain.CurrentDomain.UnhandledException you can safely cast the e.ExceptionObject to Exception without having to worry - at least if you don't have any IL code that throws other objects than Exception: Why is UnhandledExceptionEventArgs.ExceptionObject an object and not an Exception?
If you want to suppress the Windows Error Reporting dialog, you can take a look here: How to terminate a program when it crashes? (which should just fail a unit test instead of getting stuck forever)
If you have a WPF application with multiple dispatchers you can also use a Dispatcher.UnhandledException for the other dispatchers.
Thanks to #haindl for pointing out that you can also decorate handler methods with the [HandleProcessCorruptedStateExceptions]1 attribute, so I made a little test app just to confirm if things really work as they are supposed to.
1 Note: Most answers state that I should also include the [SecurityCritical] attribute, although in the tests below omitting it didn't change the behavior (the [HandleProcessCorruptedStateExceptions] alone seemed to work just fine). However, I will leave both attributes below since I am presuming all these folks knew what they were saying. That's a school example of "Copied from StackOverflow" pattern in action.
The idea is, obviously, to remove the <legacyCorruptedStateExceptionsPolicy> setting from app.config, i.e. only allow our outermost (entry-level) handler(s) to catch the exception, log it, and then fail. Adding the setting will allow your app to continue, if you catch the exception in some inner handler, and this is not what you want: the idea is just to get the accurate exception info and then die miserably.
I used the following method to throw the exception:
static void DoSomeAccessViolation()
{
// if you have any questions about why this throws,
// the answer is "42", of course
var ptr = new IntPtr(42);
Marshal.StructureToPtr(42, ptr, true);
}
1. Catching exceptions from Main:
[SecurityCritical]
[HandleProcessCorruptedStateExceptions]
static void Main(string[] args)
{
try
{
DoSomeAccessViolation();
}
catch (Exception ex)
{
// this will catch all CSEs in the main thread
Log(ex);
}
}
2. Catching all exceptions, including background threads/tasks:
// no need to add attributes here
static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += UnhandledException;
// throw on a background thread
var t = new Task(DoSomeAccessViolation);
t.Start();
t.Wait();
}
// but it's important that this method is marked
[SecurityCritical]
[HandleProcessCorruptedStateExceptions]
private static void UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
// this will catch all unhandled exceptions, including CSEs
Log(e.ExceptionObject as Exception);
}
I would recommend using just the latter approach, and removing the [HandleProcessCorruptedStateExceptions] from all other places to make sure the exception doesn't get caught at the wrong place. I.e. if you have a try/catch block somewhere and an AccessViolationException is thrown, you want CLR to skip the catch block and propagate to the UnhandledException before ending the app.
Is party over? not so fast
Microsoft: "Use application domains to isolate tasks that might bring down a process."
The program below will protect your main application/thread from unrecoverable failures without risks associated with use of HandleProcessCorruptedStateExceptions and <legacyCorruptedStateExceptionsPolicy>
public class BoundaryLessExecHelper : MarshalByRefObject
{
public void DoSomething(MethodParams parms, Action action)
{
if (action != null)
action();
parms.BeenThere = true; // example of return value
}
}
public struct MethodParams
{
public bool BeenThere { get; set; }
}
class Program
{
static void InvokeCse()
{
IntPtr ptr = new IntPtr(123);
System.Runtime.InteropServices.Marshal.StructureToPtr(123, ptr, true);
}
// This is a plain code that will prove that CSE is thrown and not handled
// this method is not a solution. Solution is below
private static void ExecInThisDomain()
{
try
{
var o = new BoundaryLessExecHelper();
var p = new MethodParams() { BeenThere = false };
Console.WriteLine("Before call");
o.DoSomething(p, CausesAccessViolation);
Console.WriteLine("After call. param been there? : " + p.BeenThere.ToString()); //never stops here
}
catch (Exception exc)
{
Console.WriteLine($"CSE: {exc.ToString()}");
}
Console.ReadLine();
}
// This is a solution for CSE not to break your app.
private static void ExecInAnotherDomain()
{
AppDomain dom = null;
try
{
dom = AppDomain.CreateDomain("newDomain");
var p = new MethodParams() { BeenThere = false };
var o = (BoundaryLessExecHelper)dom.CreateInstanceAndUnwrap(typeof(BoundaryLessExecHelper).Assembly.FullName, typeof(BoundaryLessExecHelper).FullName);
Console.WriteLine("Before call");
o.DoSomething(p, CausesAccessViolation);
Console.WriteLine("After call. param been there? : " + p.BeenThere.ToString()); // never gets to here
}
catch (Exception exc)
{
Console.WriteLine($"CSE: {exc.ToString()}");
}
finally
{
AppDomain.Unload(dom);
}
Console.ReadLine();
}
static void Main(string[] args)
{
ExecInAnotherDomain(); // this will not break app
ExecInThisDomain(); // this will
}
}

Control flow is not passing over to finally block if exception occurs in try block of try-finally

I have the following c# code:
public class Program
{
static void Main()
{
int i = 123;
string s = "Some string";
object obj = s;
try
{
// Invalid conversion;
i = (int)obj;
// The following statement is not run.
Console.WriteLine("WriteLine at the end of the try block.");
}
finally
{
Console.WriteLine("\n Finally Block executed !!!");
}
}
}
When an exception occur the program crashes without passing control to the finally block as it is understood that finally block must be executed to release the resources gained in try block.
Usually, when an unhandled exception ends an application, whether or not the finally block is run is not important. However, if you have statements in a finally block that must be run even in that situation, one solution is to add a catch block to the try-finally statement. Alternatively, you can catch the exception that might be thrown in the try block of a try-finally statement higher up the call stack. That is, you can catch the exception in the method that calls the method that contains the try-finally statement, or in the method that calls that method, or in any method in the call stack. If the exception is not caught, execution of the finally block depends on whether the operating system chooses to trigger an exception unwind operation.
Ref : https://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx
To validate this, I tried your sample like this and it executed finally block.
Try this :
public class MainClass {
public static void Main()
{
try {
Invalid();
}
catch (Exception ext) {
Console.Write(ext.Message);
}
}
public static void Invalid()
{
string message = "new string";
object o = message;
try
{
int i = (int)o;
}
finally
{
Console.WriteLine("In finally");
}
}
}

Monitor.TryEnter / Monitor.Exit and SynchronizationLockException

Is it possible to detect if the same thread trying to release the lock?
We have many places in code that looks like:
try
{
try
{
if(!Monitor.TryEnter(obj, 2000))
{
throw new Exception("can not lock");
}
}
finally
{
Monitor.Exit(obj);
}
}
catch
{
//Log
}
The above code very simplified, and actually Enter and Exit statement located in custom object (lock manager).
The problem, that in that structure, we have SynchronizationLockException when trying to "Exit", since it looks like the thread that not succeed to lock, tries to release in finally.
So the question, is how I can know if the thread who making Monitor.Exit is the same thread who did Monitor.Enter?
I thought that I can use CurrentThread.Id to sync enter and exit, but I'm not sure if it "safe" enough.
So the question, is how I can know if the thread who making Monitor.Exit is the same thread who did Monitor.Enter?
You can't, easily, as far as I'm aware. You can't find out which thread owns a monitor.
However, this is just a coding issue - you should change your code so that it doesn't even attempt to release the monitor when it shouldn't. So your code above could be rewritten as:
if (!Monitor.TryEnter(obj, 2000))
{
throw new Exception(...);
}
try
{
// Presumably other code
}
finally
{
Monitor.Exit(obj);
}
Or even better, if you're using .NET 4, use the overload of TryEnter which accepts an ret parameter:
bool gotMonitor = false;
try
{
Monitor.TryEnter(obj, ref gotMonitor);
if (!gotMonitor)
{
throw new Exception(...);
}
// Presumably other code
}
finally
{
if (gotMonitor)
{
Monitor.Exit(obj);
}
}
As you think that to put the calling of Monitor.Exit in try-catch was 'durty'(dirty?), here's a very simple idea trying to 'take the durty away'. Lock is reentrant for the same thread and if one thread acquired successfully, before it releases, attempt from another thread will fail. So that you can consider something like:
public void Exit(object key) {
if(!IsActive) {
return;
}
if(LockDictionary.ContainsKey(key)) {
var syncObject=LockDictionary[key];
if(Monitor.TryEnter(syncObject.SyncObject, 0)) {
SetLockExit(syncObject);
Monitor.Exit(syncObject.SyncObject);
Monitor.Exit(syncObject.SyncObject);
}
}
}
We call Monitor.Exit twice because we lock it twice, one in the code outer, and one just here.
I know this is an older question, but here's my answer anyway.
I would move the try-finally construct inside the if:
try
{
if(Monitor.TryEnter(obj, 2000))
{
try
{
// code here
}
finally
{
Monitor.Exit(obj);
}
}
else
{
throw new Exception("Can't acquire lock");
}
}
catch
{
// log
}

IOException getting thrown by ReaderWriteLockSlim?

I have a static class which is accessed by multiple threads and uses a ReaderWriterLockSlim in various methods to maintain thread safety. This works fine most of the time, however very intermittently I'm seeing an IOException handle is invalid error being thrown by one particular method as shown in the stack trace below. This has me greatly confused as I didn't even know that System.IO was involved in a ReaderWriterLock.
Any help at all in understanding where the error may be comming from would be greatly appreciated.
Stack Trace:
System.IO.IOException: The handle is invalid.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.Threading.EventWaitHandle.Reset()
at System.Threading.ReaderWriterLockSlim.WaitOnEvent(EventWaitHandle waitEvent, UInt32& numWaiters, Int32 millisecondsTimeout)
at System.Threading.ReaderWriterLockSlim.TryEnterUpgradeableReadLock(Int32 millisecondsTimeout)
Code:
class Class1
{
private static ReaderWriterLockSlim readwriteLock = new ReaderWriterLockSlim();
private const int readwriterlocktimeoutms = 5000;
private static void myMethod(int ID)
{
bool IsTaken = false;
bool isWriteLockTaken = false;
if (!readwriteLock.TryEnterUpgradeableReadLock(readwriterlocktimeoutms))
{
throw new Exception("SafeGetSuItem: Error acquiring read lock");
}
else { IsTaken = true; }
try
{
// do some work which may require upgrading to a write lock depending on particular conditions
}
finally
{
if (IsTaken)
{
try
{
readwriteLock.ExitUpgradeableReadLock();
IsTaken = false;
}
catch
{
throw;
}
}
}
}
}
enter code here
bool IsWriteTaken = false;
try
{
if (!readerwriterlock.TryEnterWriteLock(readerwriterlocktimeout))
{
// log the error
}
else
{
IsWriteTaken = true;
}
if (IsWriteTaken)
{
// do some work
}
}
finally
{
if (IsWriteTaken)
{
try
{
readerwriterlock.ExitWriteLock();
}
catch
{
throw;
}
}
}
This is a little weird. You may have stumbled upon a bug in the WaitHandle class. I picked this apart via Reflector and this is what I am seeing.
Calling Dispose on the ReaderWriterLockSlim will call Close on the EventWaitHandle listed in the stack trace.
Calling Close on a EventWaitHandle attempts to dispose the underlying SafeHandle.
Calling Reset on a EventWaitHandle calls directly into the ResetEvent Win32 API from kernel32.dll and passes in the SafeHandle.
I see no synchronization mechanisms in place that prevent a race between the disposing of a SafeHandle and having that instance consumed by the Win32 API.
Are you calling Dispose on the ReaderWriterLockSlim instance from another thread while TryEnterUpgradeableReadLock could be executing? This seems like the most likely scenario to me. Actually, this is the only scenario that I am seeing that would lead to an IOException being thrown.
It seems to me, based solely on my cursory analysis of the BCL code, that the IOException could be by-design, but it would make a whole lot more sense if Microsoft could somehow generate a ObjectDisposedException instead which happens on every single other attempt I have made to reproduce the problem. I would go ahead and report this to Microsoft.

Process is terminated due to StackOverflowException

This is difficult situation to explain. Have a service process that starts 2 threads, each thread loops forever but sleeps for 5 minutes each once the payload is finished.
Problem is that my second thread terminates well before the payload is even finished, for no apparent reason, and i also can't catch the exception as it seems to be triggered from outside the delegate process?
Any suggestions on how to find the problem?
The code....
public void StartService()
{
ThreadStart stRecieve = new ThreadStart(DownloadNewMail);
ThreadStart stSend = new ThreadStart(SendNewMail);
senderThread = new Thread(stRecieve);
recieverThread = new Thread(stSend);
sendStarted = true;
recieveStarted = true;
senderThread.Start();
recieverThread.Start();
}
private void DownloadNewMail()
{
while(recieveStarted)
{
//Payload....
if (recieveStarted)
{
Thread.Sleep(new TimeSpan(0, confSettings.PollInterval, 0));
}
}
}
private void SendNewMail()
{
while(sendStarted)
{
//Payload....
if (sendStarted)
{
Thread.Sleep(new TimeSpan(0, confSettings.PollInterval, 0));
}
}
}
Try to check callstack lenght in your code:
class Program
{
static void Main(string[] args)
{
try
{
Hop();
}
catch (Exception e)
{
Console.WriteLine("Exception - {0}", e);
}
}
static void Hop()
{
CheckStackTrace();
Hip();
}
static void Hip()
{
CheckStackTrace();
Hop();
}
static void CheckStackTrace()
{
StackTrace s = new StackTrace();
if (s.FrameCount > 50)
throw new Exception("Big stack!!!!");
}
}
If you are having trouble following the flow of your application's code execution, try logging the entrance of methods with a timestamp and threadid.
Also, You can't catch the exception because it is a StackOverflowException.
See msdn: "Starting with the .NET Framework version 2.0, a StackOverflowException object cannot be caught by a try-catch block and the corresponding process is terminated by default. Consequently, users are advised to write their code to detect and prevent a stack overflow. For example, if your application depends on recursion, use a counter or a state condition to terminate the recursive loop. "
Do you utlize any heavy-weight library for tasks like DownloadNewMail and SendNewMail? For example I encountered StackOverflows when running large jobs using Microsoft.SqlServer.Dts.Runtime.Package. Try running the same workload sequentially inside a command-line application to see if the issue persists.

Categories

Resources