2009-02-09 10 views
5

Me gustaría saber cómo implementar la siguiente restricción: Un método en mi Servicio de Windows no se debe volver a llamar antes de que se haya terminado la llamada anterior. El método en cuestión va a través de un par de tablas de la base de datos y es muy importante que este proceso no se vuelva a llamar antes de que se termine. Tengo una configuración que define la frecuencia con la que se activará mi servicio y, en circunstancias normales, nunca se activa antes de que la llamada anterior haya finalizado (porque el proceso completo no debe tomar más de unos minutos y el intervalo se establece en 10 minutos). bastante seguro. Supongo.¿Cómo restringir a una llamada de método a la vez?

¿Cómo implementar esto?

+0

¿Desea omitir o poner en cola las llamadas subsiguientes? –

Respuesta

11

Puede usar un named Mutex o un named Semaphor e para asegurarse de que solo un titular del Mutex/Semaphore se está ejecutando a la vez. Como señaló un comentarista, tenga en cuenta que debe tener cuidado de no abandonar un mutex o adquirir/liberar un semáforo incorrectamente.

+0

Me gusta más tu respuesta –

+0

Prefiero usar un semáforo con nombre, no hay riesgo de obtener un mutex abandonado entonces no hay necesidad de tener que lidiar con la posibilidad adicional de experimentar la excepción o tener que pensar en la propiedad. –

+0

+1 Peter Morris, añadiré un anuncio publicitario sobre la posibilidad de un semáforo con nombre, sin embargo, ellos también tienen problemas con la liberación incorrecta, etc. – user7116

1

Bueno, si todo el código está localizado, puede establecer un booleano y comprobar el booleano antes de ejecutar el método, de lo contrario puede IPC y solicitar el estado antes de la ejecución.

4

Una forma sería la de utilizar los bloqueos:

private readonly object myLock = new object(); 

private void MyMethod() 
{ 
    lock(myLock) 
    { 
     //code goes here 
    } 
} 

Esto asegura que este método no se puede ejecutar más de una vez a la vez.

+0

no se olvide de hacer myLock estático - la pregunta en realidad implica una situación multidifusión. –

+0

Creo que en realidad es una situación de procesos múltiples. – user7116

1

Algunas alternativas:

  1. Se puede poner una marca en la llamada para comprobar alguna bandera o llamar Monitor.TryEnter y regresar con un error/no hacer nada si es negativo.
  2. Puede poner en cola las llamadas (si necesita este método para ejecutar más de una vez) y solo invocar cuando se ha señalado el monitor.
  3. Si no te importa bloquear, y el método está en un hilo separado, puedes unir el hilo del método que deseas esperar.

Estoy seguro de que hay otros.

0

Esto suena como un flujo de trabajo en serie ... ¿Ha considerado utilizar un marco de flujo de trabajo?

2

En segundo lugar la sugerencia de Mutex, pero también es posible que desee echar un vistazo a las transacciones. Envolver todo el código en una transacción (esto requiere un using System.Transactions):

using(TransactionScope scope = new TransactionScope()) 
{ 
    try 
    { 
     /* ... your current code here */ 
     scope.Complete(); 
    } 
    catch (Exception e) 
    { 
     /* Any appropriate error handling/logging here */ 
    } 
    finally 
    { 
    } 
} 

Un TransactionScope bloquea automáticamente todas las tablas relacionadas. Puede reducir las restricciones y permitir que otros procesos lean, pero no escribir en los datos que está tocando su proceso. Para ello, pase opciones al constructor de TransactionsScope.

+0

Impar, todo ese mensaje no me fue enviado la primera vez, ¿error en el sistema? – rjzii

+0

Falla en mi tipeo. Accidentalmente presenté mi respuesta antes de terminar la publicación completa. –

+0

Una transacción sola no se puede usar para sincronizar el código. Solo se puede usar para * acceder * consistentemente a los datos. Cómo se bloquean las tablas, o si lo hacen, depende del nivel de aislamiento de la transacción. Eso es totalmente diferente que usar un mutex (cosas como sp_get_applock() de SQL Server Server). –

0

Si no te importa la restricción de un hilo a la vez en todo el objeto, entonces se puede utilizar:

Synchronization Contexts

  1. Haga que su clase herede de ContextBoundObject
  2. Aplicar una [Sincronización] atributo a la clase.

El CLR solo permitirá un subproceso a la vez para ejecutar código por instancia de esta clase. Los demás bloquearán hasta que la secuencia actual libere el bloqueo.

Cuestiones relacionadas