Ho un codice che quando chiamato chiama un webservice, interroga un database e recupera un valore dalla cache locale. Combina quindi i valori di ritorno di queste tre azioni per produrre il risultato. Piuttosto che eseguire queste azioni in sequenza, voglio eseguirle in modo asincrono in parallelo. Ecco alcuni codice fittizio/esempio: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));
Il problema è che l'ultima riga genera un errore perché dbResult è ancora nulla quando viene eseguito. Non appena queryDB.EndInvoke viene chiamata, WaitHandle viene segnalato e l'esecuzione continua PRIMA il risultato di queryDB.EndInvoke viene assegnato a dbResult. C'è un modo pulito/elegante intorno a questo?
Nota: Devo aggiungere che ciò influisce su dbResult semplicemente perché queryDB è l'ultimo handle di attesa da segnalare.
Update: Mentre ho accettato la risposta di Filippo che è grande, dopo i commenti di Andrey, devo aggiungere che questo funziona anche:
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));
Non una risposta, ma un aggiornamento a Fx4 renderebbe tutto molto più semplice. –