c# - run - Bloqueo de recursos con async/await
task.run c# (2)
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.
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 he considerado:
Podría crear un SynchronizationContext personalizado que clasifique todas las llamadas del secuenciador durante la duración de una secuencia en un solo subproceso. 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).
Cree un token de acceso adquirible para pasar a los métodos de Operación y probar que ha adquirido acceso. Esto tiene la desventaja de hinchar los métodos con un parámetro token.
Utilice el enfoque de token de acceso de (2), pero cree una implementación de interfaz duplicada para la interfaz de Operaciones, de modo 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.
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?
Sí, puede usar AsyncLock
, que también está disponible como parte de mi biblioteca AsyncEx . 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 verificar si el hilo actualmente en ejecución tiene un AsyncLock
específico.
Otras opciones incluyen ConcurrentExclusiveSchedulerPair
(sobre el que blogueo here ) o TPL Dataflow.
Hay SemaphoreSlim.WaitAsync
que se ajusta muy de cerca aquí. (Lo encontré en una pregunta similar ).