Ecco il codice:IAsyncResult.AsyncWaitHandle.WaitOne() completa prima del callback
class LongOp
{
//The delegate
Action longOpDelegate = LongOp.DoLongOp;
//The result
string longOpResult = null;
//The Main Method
public string CallLongOp()
{
//Call the asynchronous operation
IAsyncResult result = longOpDelegate.BeginInvoke(Callback, null);
//Wait for it to complete
result.AsyncWaitHandle.WaitOne();
//return result saved in Callback
return longOpResult;
}
//The long operation
static void DoLongOp()
{
Thread.Sleep(5000);
}
//The Callback
void Callback(IAsyncResult result)
{
longOpResult = "Completed";
this.longOpDelegate.EndInvoke(result);
}
}
Qui è il banco di prova:
[TestMethod]
public void TestBeginInvoke()
{
var longOp = new LongOp();
var result = longOp.CallLongOp();
//This can fail
Assert.IsNotNull(result);
}
Se questo viene eseguito il test case può fallire. Perché esattamente?
C'è pochissima documentazione su come delegate.BeginInvoke funziona. Qualcuno ha qualche intuizione che vorrebbero condividere?
Aggiornamento Questa è una sottile condizione di gara che non è ben documentata in MSDN o altrove. Il problema, come spiegato nella risposta accettata, è che quando l'operazione viene completata, viene segnalata la Maniglia di attesa, quindi viene eseguita la richiamata. Il segnale rilascia il thread principale in attesa e ora l'esecuzione del callback entra nella "corsa". Jeffry Richter's suggested implementation mostra ciò che accade dietro le quinte:
// If the event exists, set it
if (m_AsyncWaitHandle != null) m_AsyncWaitHandle.Set();
// If a callback method was set, call it
if (m_AsyncCallback != null) m_AsyncCallback(this);
Per una soluzione riferimento alla risposta di Ben Voigt. Tale implementazione non comporta il sovraccarico aggiuntivo di un secondo handle di attesa.
Rimuovere la richiamata e riprovare. – jgauffin
@jgauffin, se noti che la domanda non sta chiedendo "Come faccio a far funzionare tutto questo?" Chiaramente questo è un esempio forzato. –
La tua domanda è: "Se questo viene eseguito, il test case può fallire Perché esattamente?". Ho * risposto * a quello. Perché provi a mescolare due modi molto diversi di gestire un'operazione asincrona. – jgauffin