2012-02-06 21 views
8

Estoy leyendo constantemente de un archivo mapeado en memoria en el que está escribiendo otro proceso y uso un mutex para sincronizar esta operación. En mis pocas pruebas hasta ahora, esto funciona bien, pero ... ¿qué pasa si mi aplicación falla justo después de adquirir el mutex y antes de liberarlo? ¿Hay alguna forma de garantizar un lanzamiento del mutex, incluso en caso de un bloqueo?"Manejo seguro" de un Mutex?

También, ¿cómo manejaría un bloqueo del otro proceso, que podría no haber liberado el mutex todavía? ¿Debo manejar AbandonedMutexException cada vez que llamo a mutex.WaitOne()?

En este momento lo estoy haciendo similar a esto:

public MyState GetState() 
{ 
    MyState state = new State(); 
    this._mutex.WaitOne(); 
    try 
    { 
     state.X = this._mmView.ReadSingle(0); 
     state.Y = this._mmView.ReadSingle(4); 
     [..] 
    } 
    finally 
    { 
     this._mutex.ReleaseMutex(); 
    } 
    return state; 
} 

_mmView es una MemoryMappedViewAccessor que una instancia antes. Este método completo GetState() se llama cada cuadro como parte de un bucle de juego, por lo que cada pocos milisegundos.

PD: Además, ¿hay algún otro problema obvio por el que esto podría fallar, que no mencioné anteriormente?

Respuesta

11

respuesta de Eugen es correcto - el sistema operativo va a liberar el mutex para usted. Ahora piense mucho acerca de cuáles son las consecuencias de este hecho:

  • Usted tomó el mutex para asegurarse de que nadie mutaría el estado mientras estaba leyendo, o leyó el estado mientras estaba mutando. Supongamos lo último.
  • Otra aplicación quiere leer el estado, por lo que intenta tomar el mutex. Está obligado a esperar.
  • Has mutado un estado y luego se ha bloqueado.
  • El sistema operativo lanzó el mutex.
  • La otra aplicación ahora adquiere inmediatamente el mutex, y ahora está efectivamente leyendo el estado "mientras" otro proceso lo está mutando. El hecho de que el otro proceso ahora está muerto y desaparecido significa que el estado falso ahora durará para siempre, y el proceso de lectura probablemente se bloqueará y morirá horriblemente. Acaba de derrotar al sistema de seguridad proporcionado por el mutex.

En resumen, te preocupa exactamente lo incorrecto. No debe preocuparse por qué pasa si mi mutex nunca se libera. Lo peor que ocurre entonces es que todos esperan para siempre, lo cual es triste, pero eventualmente el usuario reiniciará la máquina. Debería preocuparse por que sucede si mutex se libera porque se estrelló a la mitad de una mutación. En ese escenario, los procesos de ahora probablemente se bloqueen por todos lados y los datos del usuario se corromperán permanentemente.

No entres a esa situación en primer lugar.La solución al problema es no se cuelgue cuando haya sacado un mutex para escribir. Si no escribe programas que se cuelgan, entonces no tiene que preocuparse por eso, porque no va a suceder. Así que simplemente no escribas programas que nunca se cuelgan.

+3

"no escriba programas que nunca se cuelgan", o, como dijo el maestro Zen: "Evitar el error". Buen consejo. Ejem. – mickeyf

+1

No suena muy robusto ni realista, sin embargo. ¿Qué pasa si el usuario simplemente mata el proceso a través del administrador de tareas, estrellándose a la fuerza la aplicación? – Mario

+7

@Mario: No sé lo que piensas que es poco realista; Le aseguro que este tipo de errores de corrupción de datos surgen con frecuencia y deben protegerse si se preocupa por el estado de los datos del usuario. Re: qué pasa si el usuario bloquea la aplicación? ¿Me estás preguntando qué sucede cuando el usuario hace cosas que corrompen sus propios datos? ** Sus datos se corrompe **, eso es qué. Los usuarios que no quieren que sus datos estén dañados ** no deberían eliminar sus aplicaciones **. Hay una * razón * por la cual hacerlo muestra un cuadro de diálogo que dice "podrías corromper tus datos si haces esto". –

2

Cuando finaliza un proceso al ser propietario de un mutex, el SO liberará automáticamente el mutex por usted. Pruebe esto al adquirir el mutex y luego raise new WhateverException() - el otro proceso continuará.

Lo mismo es cierto para todas las primitivas de sincronización que yo sepa