I have a console application with the following code
static void Main(string[] args) {
Method();
Console.ReadKey();
}
private static void Method() {
Task t = DoSomething();
t.Wait();
Console.WriteLine("Finished");
}
private static async Task DoSomething() {
await Task.Run(() =>
Thread.Sleep(1000));
}
Everything works exactly as I expect it to and the console displays "Finished" one second after running the program. When I move the same code into a windows application then I find that the program just stops
private void button1_Click(object sender, EventArgs e) {
Task t = DoSomething();
t.Wait();
MessageBox.Show("Finished");
}
private static async Task DoSomething() {
await Task.Run(() =>
Thread.Sleep(1000));
}
The debugger shows the current line of execution is t.Wait(), even after the Task in the DoSomething method has been run.
Is there something different that I need to do in a windows application that I don't need to do in a console application? Or am I fundamentally misunderstanding something?
That's something that happens quite often. You're causing a deadlock.
To put it simply, frameworks like WinForms and WPF "enforce" a thread synchronization context, which means that whenever you launch a new task, the rest of your code will continue on the same thread as it started. This is done to ensure that, for example, code that started on the UI thread will continue running on the same thread after the task returns.
Because you're blocking on the task (with the Wait method), and the task is trying to return a value to that blocking thread, both threads go into a deadlock state.
This behaviour doesn't happen in a console application because no thread synchronization context is enforced, the continuation of a task can run on a completely different third thread.
Stephen Cleary explains this very well here: http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
Related
I tested console application like this:
class Program
{
static void Main(string[] args)
{
Test();
Console.WriteLine("C");
Console.ReadLine();
}
static async void Test()
{
Console.WriteLine("A");
await Task.Delay(2000);
Console.WriteLine("B");
}
}
This application printed A and C immmediately then B after 2 seconds. It looks fine. But I read an article about async/await "There Is No Thread" (http://blog.stephencleary.com/2013/11/there-is-no-thread.html), it says async/await does not create additional thread.
So back to my console application, I think that the main thread is blokced on Console.ReadLine(), so the remain code in Test() (Console.WriteLine("B")) is not executed until Console.ReadLine() is complete. But actual result is different, the remain code is executed regardless of the blocking of main thread.
I want to know that await works like CPU interrupt, so the instruction pointer is moved to the remain code(Console.WriteLine("B");) and moved back to interrupted position(Console.ReadLine();) after execution?
Unlike a Windows form app, console applications don't have a single "blessed" thread (the UI thread). As such, no special synchronization context is employed by default in console applications and so the continuations that await makes use of are in fact scheduled using the thread pool.
So there's no need to "interrupt" the thread that's currently waiting on Console.ReadLine - another thread is used instead.
Hi i need your help guys,
i declared new Task inside my main method like this:
static void Main(string[] args)
{
Task firstTask = Task.Factory.StartNew(()getPackage(packageId));
Task secondTask=firstTask.ContinueWith((_=>UpdatePackage(myPackage)));
}
My problem is, the main thread terminates before my task completes its action.
How should I wait Task to complete its action before terminating the main thread?
Add the following code to make your main thread block until you hit enter in the command window.
Console.Readline();
UPDATE:
If you want a non-interactive solution, then you could just wait for all the tasks to complete.
Task.WaitAll(firstTask, secondTask);
You can use an alternate paradigm for dealing with this.
static void Main(string[] args)
{
MainAsync().Wait();
}
static async Task MainAsync()
{
Task firstTask = new Task(()=>getPackage(packageId));
firstTask.ContinueWith(()=>UpdatePackage(myPackage)));
await firstTask.Run();
}
Be careful with mixing asynchronous and synchronous code like this, but, for your purposes, this should work fine (if this were winforms or WPF, you might have to worry about messaging to the UI thread, but that's not relevant here.
Assign your task to a Thread and then in your main call the .Join() function of the created thread (after it has been started of course). That way the application will wait until the task is over before ending.
This solution is more complexe than a Console.ReadLine but allows you to leave when the ask is over not before and not after.
I have been working around this problem for a while, but now I would really like to understand what goes wrong. I have a rather simple application (it's a turtoise SVN plugin for youtrack, but I can reproduce the problem with a trivial winforms app).
I have an async method ResolveIssue
public async Task<bool> ResolveIssue(Issue issue, int revision, string[] pathList)
{
await Task.Delay(1000);
return true;
}
All I have to do to create a deadlock is call this async method in a Button event handler, and call Task.Wait or Task.Result, like this
private void buttonOk_Click(object sender, System.EventArgs e)
{
var asyncResolvedIssue = api.ResolveIssue(issue, revision, pathList);
if (asyncResolvedIssue.Result) {} // <== deadlock!
}
Now I understand it's rather weird to have an async method and actively wait for it, but why would it generate a deadlock?!
Your problem is because you are blocking the UI thread when you call .Result and you told the continuation after Task.Delay to run on the UI thread. So you are blocking the UI waiting for a task that is blocked on waiting for the UI to become free, a classic deadlock.
Two solutions. First make the button click async too.
private async void buttonOk_Click(object sender, System.EventArgs e)
{
var asyncResolvedIssue = api.ResolveIssue(issue, revision, pathList);
if (await asyncResolvedIssue) {} // <== no deadlock!
}
Event handlers are the only place you are allowed to do async void.
The other option is tell Task.Delay it does not need to have the rest of its function run on the UI thread by setting ConfigureAwait(bool) to false.
public async Task<bool> ResolveIssue(Issue issue, int revision, string[] pathList)
{
await Task.Delay(1000).ConfigureAwait(false);
return true;
}
Now the line of code after the Task.Delay will run on a threadpool thread instead of the UI thread and will not be blocked by the fact that the UI thread is currently blocked.
Given the following code, why does ask.WhenAny never return when provided with a Task.Delay of 1 second? Technically I'm not sure if it does return after a extended amount of time, but it doesn't after 15 seconds or so after which I manually kill the process. According to the documentation I shouldn't be required to manually start the delayTask, and in fact I receive a exception if I try to do so manually.
The code is being called from the UI thread when a user selects a context menu item in a WPF application, although it works fine if I have the click method specified for the context menu item run this code in a new thread.
public void ContextMenuItem_Click(object sender, RoutedEventArgs e)
{
...
SomeMethod();
...
}
public void SomeMethod()
{
...
SomeOtherMethod();
....
}
public void SomeOtherMethod()
{
...
TcpClient client = Connect().Result;
...
}
//In case you're wondering about the override below, these methods are in
//different classes i've just simplified things here a bit so I'm not posting
//pages worth of code.
public override async Task<TcpClient> Connect()
{
...
Task connectTask = tcpClient.ConnectAsync(URI.Host, URI.Port);
Task delayTask = Task.Delay(1000);
if (await Task.WhenAny(connectTask, delayTask) == connectTask)
{
Console.Write("Connected\n");
...
return tcpClient;
}
Console.Write("Timed out\n");
...
return null;
}
If I change ContextMenuItem_Click to the following it works fine
public void ContextMenuItem_Click(object sender, RoutedEventArgs e)
{
...
new Thread(() => SomeMethod()).Start();
...
}
I predict that further up your call stack, you're calling Task.Wait or Task<T>.Result. This will cause a deadlock that I explain in full on my blog.
In short, what happens is that await will (by default) capture the current "context" and use that to resume its async method. In this example, the "context" is the WPF UI context.
So, when your code does its await on the task returned by WhenAll, it captures the WPF UI context. Later, when that task completes, it will attempt to resume on the UI thread. However, if the UI thread is blocked (i.e., in a call to Wait or Result), then the async method cannot continue running and will never complete the task it returned.
The proper solution is to use await instead of Wait or Result. This means your calling code will need to be async, and it will propagate through your code base. Eventually, you'll need to decide how to make your UI asynchronous, which is an art in itself. At least to start with, you'll need an async void event handler or some kind of an asynchronous MVVM command (I explore async MVVM commands in an MSDN article). From there you'll need to design a proper asynchronous UI; i.e., how your UI looks and what actions it permits when asynchronous operations are in progress.
I'm currently writing a C# console app that generates a number of URLs that point to different images on a web site and then downloads as byte streams using WebClient.DownloadDataAsync().
My issue is that once the first asynchronous call is made, the console app considers the program to be completed and terminates before the asynchronous call can return. By using a Console.Read() I can force the console to stay open but this doesn't seem like very good design. Furthermore if the user hits enter during the process (while the console is waiting for input) the program will terminate.
Is there a better way to prevent the console from closing while I am waiting for an asynchronous call to return?
Edit: the calls are asynchronous because I am providing a status indicator via the console to the user while the downloads take place.
Yes. Use a ManualResetEvent, and have the async callback call event.Set(). If the Main routine blocks on event.WaitOne(), it won't exit until the async code completes.
The basic pseudo-code would look like:
static ManualResetEvent resetEvent = new ManualResetEvent(false);
static void Main()
{
CallAsyncMethod();
resetEvent.WaitOne(); // Blocks until "set"
}
void DownloadDataCallback()
{
// Do your processing on completion...
resetEvent.Set(); // Allow the program to exit
}
Another option is to just call an async Main method and wait on the task returned.
static void Main(string[] args)
{
MainAsync(args).Wait();
}
static async Task MainAsync(string[] args)
{
// .. code goes here
}
Since .NET 4.5 you can now call GetAwaiter().GetResult()
static void Main(string[] args)
{
MainAsync(args).GetAwaiter().GetResult();
}
What is the difference between .Wait() vs .GetAwaiter().GetResult()?
If that is all your application is doing, I would suggest leaving out the async call; you specifically want the app to 'hang' until the download is complete, so using an async operation is contrary to what you want here, especially in a console app.
It should be stated that in C# 7.1 Main can now be marked as async.
static async Task Main()
{
await LongRunningOperation();
}