Reputation: 1161
I have the need to move some processes to async. I have 5 methods that I need to call individually and have run in the background so the user can continue on with their work.
The test code below seems to work... but I haven't been able to figure out how to return information (message) indicating that the a task has completed. The class will be called from a separate windows form so that the progress can be displayed....
from the form:
async void BtnGo_Click(object sender, System.EventArgs e)
{
label2.Text = @"Starting tasks...";
var progress = new Progress<string>(
p =>
{
label2.Text = p;
});
await TestTask.MyTestMain(progress);
}
the class:
public static class TestTask
{
public static Task MyTestMain(IProgress<string> pProgress)
{
return SomethingAsync(pProgress);
}
private static async Task SomethingAsync(IProgress<string> pProgress)
{
var t1 = SomeThing1(pProgress);
var t2 = SomeThing2(pProgress);
await Task.WhenAll(t1, t2);
if (pProgress != null) pProgress.Report(@"all tasks completed");
}
private static async Task SomeThing1()
{
await Task.Delay(9000);
var filename = @"c:\temp\tt1.txt";
if (File.Exists(filename))
File.Delete(filename);
using (TextWriter tw = new StreamWriter(filename))
{
await tw.WriteLineAsync(DateTime.Now.ToLongDateString());
}
if (pProgress != null) pProgress.Report(@"t1 completed");
}
private static async Task SomeThing2()
{
await Task.Delay(7000);
var filename = @"c:\temp\tt2.txt";
if (File.Exists(filename))
File.Delete(filename);
using (TextWriter tw = new StreamWriter(filename))
{
await tw.WriteLineAsync(DateTime.Now.ToLongDateString());
}
if (pProgress != null) pProgress.Report(@"t2 completed");
}
}
I would like know when each task has completed. Any help or direction would be appreciated.
EDIT I have edited this post to reflect my changes... I still cannot get a progress report back to the UI... any thoughts?
Upvotes: 2
Views: 997
Reputation: 149656
You're doing IO bound work, you don't need to use thread-pool threads.
Transform your methods to use the async APIs of StreamWriter
:
private static async Task FirstThingAsync()
{
var filename = @"c:\temp\tt1.txt";
if (File.Exists(filename))
File.Delete(filename);
using (TextWriter tw = new StreamWriter(filename))
{
await tw.WriteLineAsync(DateTime.Now);
}
}
Same for your second method, and then you can asynchronously wait on them concurrently:
private static async Task SomethingAsync()
{
var firstThing = FirstThingAsync();
var secondThing = SecondThingAsync();
await Task.WhenAll(firstThing, secondThing);
}
Edit:
You're never reaching your first Progress.Report
call because your code is throwing an InvalidOperationException
when you call t.Start()
on a promise-style task:
t1.Start();
await t1;
t2.Start();
await t2;
The task returned from both method calls is a "hot task", meaning it's operation is already started. The docs on Task.Start
say:
InvalidOperationException: The Task is not in a valid state to be started. It may have already been started, executed, or canceled, or it may have been created in a manner that doesn't support direct scheduling.
The reason you're not seeing that exception is because you're swallowing it:
var t = SomethingAsync(pProgress);
When you don't await on the async operation. Your method calls should look like this:
public static Task MyTestMain(IProgress<string> pProgress)
{
return SomethingAsync(pProgress);
}
async void BtnGo_Click(object sender, System.EventArgs e)
{
label2.Text = @"Starting tasks...";
var progress = new Progress<string>(
p =>
{
label2.Text = p;
});
await TestTask.MyTestMain(progress);
}
Upvotes: 1