Tengo un código que cuando se llama llama a un servicio web, consulta una base de datos y obtiene un valor de la memoria caché local. Luego combina los valores de retorno de estas tres acciones para producir su resultado. En lugar de realizar estas acciones secuencialmente, quiero realizarlas de forma asincrónica en paralelo. Aquí hay algo de código ficticio/ejemplo:C# threading async problem
var waitHandles = new List<WaitHandle>();
var wsResult = 0;
Func<int> callWebService = CallWebService;
var wsAsyncResult = callWebService.BeginInvoke(res => { wsResult = callWebService.EndInvoke(res); }, null);
waitHandles.Add(wsAsyncResult.AsyncWaitHandle);
string dbResult = null;
Func<string> queryDB = QueryDB;
var dbAsyncResult = queryDB.BeginInvoke(res => { dbResult = queryDB.EndInvoke(res); }, null);
waitHandles.Add(dbAsyncResult.AsyncWaitHandle);
var cacheResult = "";
Func<string> queryLocalCache = QueryLocalCache;
var cacheAsyncResult = queryLocalCache.BeginInvoke(res => { cacheResult = queryLocalCache.EndInvoke(res); }, null);
waitHandles.Add(cacheAsyncResult.AsyncWaitHandle);
WaitHandle.WaitAll(waitHandles.ToArray());
Console.WriteLine(string.Format(dbResult, wsResult, cacheResult));
El problema es que la última línea genera un error porque dbResult sigue siendo nula cuando es ejecutado. Tan pronto como se invoca queryDB.EndInvoke, se señala el WaitHandle y la ejecución continúa ANTES de que el resultado de queryDB.EndInvoke se asigne a dbResult. ¿Hay una manera ordenada/elegante alrededor de esto?
Nota: Debo agregar que esto afecta a dbResult simplemente porque la queryDB es el último identificador de espera para ser señalado.
Actualización: Aunque acepté la respuesta de Felipe que es grande, a raíz de los comentarios de Andrei, debo añadir que esto también funciona:
var waitHandles = new List<WaitHandle>();
var wsResult = 0;
Func<int> callWebService = CallWebService;
var wsAsyncResult = callWebService.BeginInvoke(null, null);
waitHandles.Add(wsAsyncResult.AsyncWaitHandle);
string dbResult = null;
Func<string> queryDB = QueryDB;
var dbAsyncResult = queryDB.BeginInvoke(null, null);
waitHandles.Add(dbAsyncResult.AsyncWaitHandle);
var cacheResult = "";
Func<string> queryLocalCache = QueryLocalCache;
var cacheAsyncResult = queryLocalCache.BeginInvoke(null, null);
waitHandles.Add(cacheAsyncResult.AsyncWaitHandle);
WaitHandle.WaitAll(waitHandles.ToArray());
var wsResult = callWebService.EndInvoke(wsAsyncResult);
var dbResult = queryDB.EndInvoke(dbAsyncResult);
var cacheResult = queryLocalCache.EndInvoke(cacheAsyncResult);
Console.WriteLine(string.Format(dbResult, wsResult, cacheResult));
No es una respuesta, pero una actualización a Fx4 lo haría mucho más fácil. –