waitone sirve que para net lock ejemplo c# .net multithreading mutex

c# - sirve - Se llamó al método de sincronización de objetos desde un bloque de código no sincronizado. Excepción en Mutex.Release()



para que sirve mutex en c# (7)

He encontrado diferentes artículos sobre esta excepción, pero ninguno de ellos fue mi caso. Aquí está el código fuente:

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(); La función ejecuta las solicitudes al servidor y genera algunos eventos, uno de los cuales es el evento CtiCallsRetrieve . Y necesito liberar el mutex cuando se dispara este evento. Pero al llamar a la función mutex.Release () se lanza la excepción. CreateFilteredCtiCallLogSync funciona de forma síncrona. ¿Cuál es el problema?


El uso de una bandera para intentar monitorear el estado del objeto de sincronización del kernel simplemente no funcionará; el punto de usar esas llamadas de sincronización es que funcionen correctamente sin ninguna comprobación explícita. La configuración de las banderas solo causará problemas intermitentes porque la bandera puede cambiarse de manera inadecuada debido a interrupciones entre la verificación de la bandera y la acción sobre ella.

Un mutex solo puede ser liberado por la amenaza que lo adquirió. Si su devolución de llamada es llamada por un subproceso diferente, (uno interno a CreateFilteredCtiCallLogSync () o un grupo de subprocesos del kernel), la versión fallará.

No está claro exactamente lo que estás intentando hacer. Presumiblemente, ¿desea serializar el acceso a CreateFilteredCtiCallLogSync () y los indicadores de devolución de llamada de que la instancia está disponible para su reutilización? Si es así, podrías usar un semáforo en su lugar - init. a una unidad, espérelo al inicio y suéltelo en la devolución de llamada.

¿Hay algún problema en el que a veces no se llama a la devolución de llamada y, por lo tanto, a la opción try / finally / release? Si es así, esta salida parece un poco dudosa si la devolución de llamada es asíncrona y puede ser llamada por otro hilo después de que el hilo de configuración haya abandonado la función.


He encontrado el problema. Primero varias cosas sobre la clase filterCtiCallLog. Lo he diseñado para que funcione tanto asíncrono como síncrono. Para primero he escrito código para ejecución asíncrona. Necesitaba una manera de desencadenar eventos del subproceso del trabajador hijo al padre, para informar el estado de trabajo. Para esto he usado la clase AsyncOperation y su método posterior. Aquí está la parte del código para desencadenar el evento CtiCallsRetrieved.

public class FilterCtiCallLog { private int RequestCount = 0; private AsyncOperation createCallsAsync = null; private SendOrPostCallback ctiCallsRetrievedPost; public void CreateFilteredCtiCallLogSync() { createCallsAsync = AsyncOperationManager.CreateOperation(null); ctiCallsRetrievedPost = new SendOrPostCallback(CtiCallsRetrievedPost); CreateFilteredCtiCallLog(); } private void CreateFilteredCtiCallLog() { int count=0; //do the job //............ //........... //Raise the event createCallsAsync.Post(CtiCallsRetrievedPost, new CtiCallsRetrievedEventArgs(count)); //........... //........... } public event EventHandler<CtiCallsRetrievedEventArgs> CtiCallsRetrieved; private void CtiCallsRetrievedPost(object state) { CtiCallsRetrievedEventArgs args = state as CtiCallsRetrievedEventArgs; if (CtiCallsRetrieved != null) CtiCallsRetrieved(this, args); } }

Como puedes ver el código se está ejecutando de forma síncrona. El problema aquí está en el método AsyncOperation.Post() . Supuse que si se llama en el subproceso principal, actuará como un simple desencadenante del evento, no publicándolo en el subproceso principal. Sin embargo no fue el caso. No sé cómo está funcionando, pero he cambiado el código para comprobar si CreateFilteredCtiCallLog se llama sync o async. Y si es una llamada asíncrona, AsyncOperation.Post método AsyncOperation.Post , si no, simplemente EventHandler el EventHandler si no es null . Aquí está el código corregido

public class FilterCtiCallLog { private int RequestCount = 0; private AsyncOperation createCallsAsync = null; private SendOrPostCallback ctiCallsRetrievedPost; public void CreateFilteredCtiCallLogSync() { createCallsAsync = AsyncOperationManager.CreateOperation(null); ctiCallsRetrievedPost = new SendOrPostCallback(CtiCallsRetrievedPost); CreateFilteredCtiCallLog(false); } private void CreateFilteredCtiCallLog(bool isAsync) { int count=0; //do the job //............ //........... //Raise the event RaiseEvent(CtiCallsRetrievedPost, new CtiCallsRetrievedEventArgs(count),isAsync); //........... //........... } public event EventHandler<CtiCallsRetrievedEventArgs> CtiCallsRetrieved; private void RaiseEvent(SendOrPostCallback callback, object state, bool isAsync) { if (isAsync) createCallsAsync.Post(callback, state); else callback(state); } private void CtiCallsRetrievedPost(object state) { CtiCallsRetrievedEventArgs args = state as CtiCallsRetrievedEventArgs; if (CtiCallsRetrieved != null) CtiCallsRetrieved(this, args); } }

Gracias a todos por las respuestas!


He visto que esto sucede cuando bloquea el código usando un Monitor, luego llama a un código asíncrono y obtiene esto, cuando usa un bloqueo (objeto), obtiene un error del compilador, sin embargo, entre monitor.enter (objeto) y Monitor.Exist (objeto ) El compilador no se queja ... desafortunadamente.


Mantener un error alrededor que indique que el mutex es de su propiedad es un grave error. Usted no está haciendo el hilo de bool seguro. Te metiste en este pickle porque estás usando el objeto de sincronización incorrecto. Un mutex tiene afinidad de hilos, el propietario de un mutex es un hilo. El hilo que lo adquirió también debe ser el que llama a ReleaseMutex (). Es por eso que su código de bombas.

Es muy probable que necesite un evento aquí, use AutoResetEvent. Créelo en el hilo principal, llame a Set () en el trabajador, WaitOne () en el hilo principal para esperar a que el trabajador complete su trabajo. Y deséchelo después. También tenga en cuenta que el uso de un hilo para realizar un trabajo y que su hilo principal espere su finalización no es productivo. Usted también podría tener el hilo principal para hacer el trabajo.

Si realmente está haciendo esto para proteger el acceso a un objeto que no es seguro para subprocesos (no está claro), use la instrucción de bloqueo .


Otra razón por la cual esta excepción puede ocurrir:

if (Monitor.TryEnter(_lock)) { try { ... await MyMethodAsync(); ... } finally { Monitor.Exit(_lock); } }

Obtengo esta excepción en Monitor.Exit cuando después de "esperar" otro subproceso continúa su ejecución.


Solo tuve esta una o dos veces, y en todos los casos surgió al intentar liberar un mutex que no tenía.

¿Está seguro de que los eventos aparecen en el mismo hilo en el que se adquirió el mutex? ¿Aunque menciona que filterCtiCallLog.CreateFilteredCtiCallLogSync() es una llamada de bloqueo, tal vez genera subprocesos de trabajo que provocan el evento?


Tal vez no sea el mensaje de error más significativo, he visto que esto sucede en algún código de terceros como se muestra a continuación.

object obj = new object(); lock (obj) { //do something Monitor.Exit(obj);//obj released }//exception happens here, when trying to release obj