2012-10-02 33 views
31

Tengo una aplicación donde tengo un recurso compartido (un sistema de movimiento) al que pueden acceder varios clientes. Tengo operaciones individuales que requieren acceso al sistema por la duración del movimiento y que deben arrojar excepciones 'Ocupadas' si se solicitan operaciones conflictivas al mismo tiempo. También tengo Sequencers que necesitan adquirir acceso exclusivo al sistema Motion para la ejecución de varias Operaciones, intercaladas con otras acciones; durante toda la secuencia, ningún otro cliente debería poder ejecutar Operaciones.Bloqueo de recursos con async/await

Tradicionalmente me he acercado a esto usando Thread-affinity, por lo que un Thread puede solicitar acceso exclusivo y ejecutar llamadas de bloqueo correspondientes a las operaciones. Mientras que el subproceso tiene acceso, ningún otro subproceso puede usar el recurso. El problema que estoy teniendo ahora es que me he movido hacia la implementación de mi sistema usando patrones async/await, para permitir una implementación más limpia del secuenciador. El problema es que ahora mi secuenciador no siempre se ejecuta en el mismo hilo; el hilo activo puede cambiar durante el curso de las devoluciones de llamada, por lo que ya no es fácil determinar si estoy en un contexto válido para seguir ejecutando operaciones. Un elemento a tener en cuenta es que algunas de las operaciones mismas están compuestas de espera, lo que significa que tanto las secuencias como las operaciones individuales pueden abarcar múltiples hilos.

Mi pregunta: ¿Alguien sabe de un buen patrón para tratar de adquirir acceso exclusivo en presencia de cambio de hilo debido a async/await?

Como referencia, algunas cosas que hemos considerado:

  1. que podría crear una SynchronizationContext a medida que reúne todas secuenciador llama a la duración de una secuencia de nuevo a un solo hilo. Esto tiene el beneficio de permitirme reutilizar mi código de gestión de acceso de afinidad de hebras existente. La desventaja es que esto requerirá dedicar un subproceso cada vez que haga una secuencia o una operación (ya que las operaciones también pueden abarcar varios subprocesos).

  2. Cree un token de acceso para poder pasar a los métodos de operación para comprobar que tiene acceso adquirido. Esto tiene la desventaja de hinchar los métodos con un parámetro token.

  3. Utilice el enfoque de token de acceso de (2), pero cree una implementación de interfaz duplicada para la interfaz de Operaciones para que un contenedor pueda crearse una instancia con el token 'horneado'. Esto crea un feo código de pegamento, pero limpia el código del secuenciador para que ya no tenga que pasar un token a cada método.

Respuesta

22

Mi pregunta: ¿Alguien sabe de un buen patrón para hacer frente a la adquisición de acceso exclusivo en presencia de conmutación hilo debido al asíncrono/aguardan?

Sí, puede usar AsyncLock, que también está disponible como parte de mi AsyncEx library. Si desea tener un tipo de operación "TryLock", entonces puede que tenga que crear su propia primitiva.

Perder parte de la capacidad de realizar comprobaciones de seguridad: no hay forma de comprobar si el subproceso en ejecución tiene un AsyncLock específico.

Otras opciones incluyen ConcurrentExclusiveSchedulerPair (que blogueo acerca de here) o TPL Dataflow.

+0

Voy a marcar esto como la respuesta para la lectura útil. Finalmente terminé creando proxies para las interfaces que incluyen verificaciones de acceso. Luego puedo distribuir un proxy especial de 'acceso exclusivo' que evita que las otras instancias proxy utilicen el sistema mientras está activo. –