visual studio microsoft español descargar community c# windows-phone-8 async-await semaphore

c# - microsoft - visual studio installer



Bloquear con llamadas asincrónicas anidadas (2)

Estoy trabajando en una aplicación WindowsPhone8 de múltiples hilos que tiene secciones críticas dentro de los métodos asíncronos.

¿Alguien sabe de una forma de usar semáforos / mutexes correctamente en C # donde está utilizando llamadas asincrónicas anidadas donde el método interno puede estar adquiriendo el mismo bloqueo que ya adquirió en la pila de llamadas? Pensé que el SemaphoreSlim podría ser la respuesta, pero parece que causa un punto muerto.

public class Foo { SemaphoreSlim _lock = new SemaphoreSlim(1); public async Task Bar() { await _lock.WaitAsync(); await BarInternal(); _lock.Release(); } public async Task BarInternal() { await _lock.WaitAsync(); // deadlock // DO work _lock.Release(); } }


Esto es lo que hice en tal situación (aún así, no tengo experiencia con las tareas, así que no me ganes ;-)
Así que, básicamente, tiene que mover la implementación real a métodos que no sean de bloqueo y usarlos en todos los métodos que adquieren un bloqueo.

public class Foo { SemaphoreSlim _lock = new SemaphoreSlim(1); public async Task Bar() { await _lock.WaitAsync(); await BarNoLock(); _lock.Release(); } public async Task BarInternal() { await _lock.WaitAsync(); // no deadlock await BarNoLock(); _lock.Release(); } private async Task BarNoLock() { // do the work } }


Los bloqueos recursivos son una muy mala idea (IMO, el enlace es a mi propio blog). Esto es especialmente cierto para el código async . Es muy difícil conseguir que funcionen las cerraduras recursivas compatibles con la async . Aquí tengo una prueba de concepto pero una advertencia justa: no recomiendo usar este código en producción, este código no se incluirá en AsyncEx, y no se prueba exhaustivamente.

Lo que debe hacer en su lugar es reestructurar su código como se indica en @svick. Algo como esto:

public async Task Bar() { await _lock.WaitAsync(); await BarInternal_UnderLock(); _lock.Release(); } public async Task BarInternal() { await _lock.WaitAsync(); await BarInternal_UnderLock(); _lock.Release(); } private async Task BarInternal_UnderLock() { // DO work }