I have found different articles about this exception but none of them was my case. Here is the source code:
class Program { private static Mutex mutex; private static bool mutexIsLocked = false; static void Main(string[] args) { ICrmService crmService = new ArmenianSoftware.Crm.Common.CrmServiceWrapper(GetCrmService("Armsoft", "crmserver")); //Lock mutex for concurrent access to workflow mutex = new Mutex(true, "ArmenianSoftware.Crm.Common.FilterCtiCallLogActivity"); mutexIsLocked = true; //Create object for updating filtered cti call log ArmenianSoftware.Crm.Common.FilterCtiCallLog filterCtiCallLog = new ArmenianSoftware.Crm.Common.FilterCtiCallLog(crmService); //Bind events filterCtiCallLog.CtiCallsRetrieved += new EventHandler<ArmenianSoftware.Crm.Common.CtiCallsRetrievedEventArgs>(filterCtiCallLog_CtiCallsRetrieved); //Execute filter try { filterCtiCallLog.CreateFilteredCtiCallLogSync(); } catch (Exception ex) { throw ex; } finally { if (mutexIsLocked) { mutexIsLocked = false; mutex.ReleaseMutex(); } } } static void filterCtiCallLog_CtiCallsRetrieved(object sender, ArmenianSoftware.Crm.Common.CtiCallsRetrievedEventArgs e) { tryasasas { if (mutexIsLocked) { mutexIsLocked = false; mutex.ReleaseMutex(); } } catch (Exception ex) { throw ex; } } }
filterCtiCallLog.CreateFilteredCtiCallLogSync();
function executes requests to server, and raises some events, one of which is CtiCallsRetrieve
event. And I need to release the mutex when this event is fired. But on calling the mutex.Release() function exception is thrown. CreateFilteredCtiCallLogSync
works synchronously. What is the problem?
Keeping a bool around that indicates that the mutex is owned is a grave mistake. You are not making the bool thread-safe. You got into this pickle because you are using the wrong synchronization object. A mutex has thread-affinity, the owner of a mutex is a thread. The thread that acquired it must also be the one that calls ReleaseMutex(). Which is why your code bombs.
You in all likelihood need an event here, use AutoResetEvent. Create it in the main thread, call Set() in the worker, WaitOne() in the main thread to wait for the worker to complete its job. And dispose it afterwards. Also note that using a thread to perform a job and having your main thread wait for its completion is not productive. You might as well have the main thread do the job.
If you are actually doing this to protect access to an object that's not thread-safe (it isn't clear) then use the lock statement.
Another reason why this exception may occur:
if (Monitor.TryEnter(_lock)) { try { ... await MyMethodAsync(); ... } finally { Monitor.Exit(_lock); } }
I get this exception on Monitor.Exit when after 'await' another thread continues execution.
Edit: Use SemaphoreSlim, because it doesn't require releasing thread to be the same.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With