I am starting several tasks using Task.Run()
. Within each of these tasks, I define an event handler for InstallCompleted
. Then, I await
for these tasks to finish. The tricky bit is that the installModule.Install()
method seen below returns immediately because internally it calls a OneWay
WCF service call.
So, how do I await
until all instances of installModule
in each task above have fired their respective InstallCompleted
events? If there is a better way to accomplish this, I'm all ears.
var installTasks = new List<Task>();
foreach (var targetMachine in vm.TargetMachines)
{
var installTask = Task.Run(() =>
{
foreach (var module in Modules)
{
var installModule = module as IInstallModule; // copy closure variable
if (installModule == null)
continue;
installModule.InstallCompleted += (s, e) =>
{
//TODO set some flag indicating this install is complete
};
var ip = new Progress<InstallProgress>();
installModule.Install(targetMachine.MachineName, ip);
}
});
installTasks.Add(installTask);
}
await Task.WhenAll(installTasks); // unblocks immediately because installModule.Install() above returns immediately
Whenever you're interoperating async
with another kind of asynchronous API , you can use TaskCompletionSource<T>
as an asynchronous one-time signal. Personally, I like to do this as an extension method:
public static Task<InstallCompletedResult> InstallAsync(
this IInstallModule module, string machineName,
IProgress<InstallProgress> progress = null)
{
var tcs = new TaskCompletionSource<InstallCompletedResult>();
InstallCompletedEventHandler handler = null;
handler = (s, e) =>
{
module.InstallCompleted -= handler;
if (e.Exception != null)
tcs.TrySetException(e.Exception);
else
tcs.TrySetResult(e.Result);
};
module.InstallCompleted += handler;
module.Install(machineName, progress);
return tcs.Task;
}
Once you have the interop piece in, consuming it is quite straightforward:
var installTask = Task.Run(async () =>
{
var tasks = new List<Task>();
foreach (var module in Modules)
{
var installModule = module as IInstallModule; // copy closure variable
if (installModule == null)
continue;
var ip = new Progress<InstallProgress>();
tasks.Add(installModule.InstallAsync(targetMachine.MachineName, ip));
}
});
Or, more simply:
var installTask = Task.Run(async () =>
{
var tasks = Modules.OfType<IInstallModule>()
.Select(module => module.InstallAsync(targetMachine.MachineName,
new Progress<InstallProgress>()));
await Task.WhenAll(tasks);
});
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.