I want to pause the program so it does not close. I have a code running in the main thread. Tried this way, but this code instantly skips and the program closes instead of waiting.
How can I make it wait for the WaitMy method to complete?
static void Main(string[] args)
{
//any code here...
Console.WriteLine("Discovery started");
WaitMy();
}
private async static void WaitMy()
{
//await Task.Delay(30 * 1000);
await Task.Run(async () => await Task.Delay(30 * 1000));
}
The application runs with .net 4.5.
Change the code to following to make it work:
static async Task Main(string[] args)
{
//any code here...
Console.WriteLine("Discovery started");
await WaitMy();
}
How this works ?
You need C# 7.1 or later versions
Now Main method can be declared async and has return type as Task for introducing await
It will simply let the delay execute asynchronously, but will renter the main context for continuation, which will not exit
Another suggestion would be, you just need await Task.Delay(30 * 1000), wrapping inside the Task.Run is not required here
You are using Task Programming Library. What happens here is that, in your WaitMy method, you are scheduling a task to be executed (await Task.Run(...)). The task is being executed on a background thread.
In the meanwhile, the Main method continues its execution after the call to the WaitMy method.
The Main method ends right after, so the foreground thread is terminated, and all the background threads associated to its process are terminated too.
If you just want to perform a delay, just use:
System.Threading.Thread.Sleep(30 * 1000);
in the Main method, instead of calling WaitMy.
The method WaitMy can return a Task instance so you can have your main thread wait for it to be completed.
static void Main(string[] args)
{
//any code here...
Console.WriteLine("Discovery started");
var task = WaitMy();
task.Wait();
Console.WriteLine("And done :)");
}
private static Task WaitMy()
{
//await Task.Delay(30 * 1000);
return Task.Run(async () => await Task.Delay(30 * 1000));
}
If you just want the program to wait before terminating a simple answer would be to use
Console.ReadKey();
If you are curious why program terminates without waiting it is because you delegate waiting to ThreadPool by using Task.Run so waiting occurs on another thread an your application simply terminates before it can receive any result from ThreadPool
Related
I do not understand how is the control returned to the caller when using async- await, since when i execute this code, the first thread gets practically destroyed when calling task inside the awaited method, and the thread that gives the result executes all remaining code.Below i have also drawn a diagram of how i thought the execution is, but it seems it is wrong.
Assumed workflow according to "returning control to the caller":
Results
Main
public static string GetThreadId => Thread.CurrentThread.ManagedThreadId.ToString();
static async Task Main(string[] args) {
Console.WriteLine("From main before async call , Thread:" + GetThreadId);
string myresult = await TestAsyncSimple();
Console.WriteLine("From main after async call ,Thread:" + GetThreadId);
Console.WriteLine("ResultComputed:" + myresult+",Thread:"+GetThreadId);
Console.ReadKey();
}
Async Task
public static async Task<string> TestAsyncSimple() {
Console.WriteLine("From TestAsyncSimple before delay,Thread:" + GetThreadId);
string result=await Task.Factory.StartNew(() => {
Task.Delay(5000);
Console.WriteLine("From TestAsyncSimple inside Task,Thread:" + GetThreadId);
return "tadaa";
});
Console.WriteLine("From TestAsyncSimple after delay,Thread:" + GetThreadId);
return result;
}
Can anyone point me to the right direction?Also what causes the new thread to get spawned?Always when starting a Task ?Are there other "triggers" besides tasks that create new threads which will execute the remaining code?
async Main method is converted to something like this:
static void Main() {
RealMain().GetAwaiter().GetResult();
}
static async Task RealMain() {
// code from async Main
}
With that in mind, at "From main before async call" point you are on main application thread (id 1). This is regular (non thread pool) thread. You will be on this thread until
await Task.Factory.StartNew(...)
At this point, StartNew starts a new task which will run on a thread pool thread, which is created or grabbed from pool if already available. This is thread 3 in your example.
When you reach await - control is returned back to the caller, where caller in this case is thread 1. What this thread does after await is reched? It's blocked here:
RealMain().GetAwaiter().GetResult();
waiting for result of RealMain.
Now thread 3 has finished execution but TestAsyncSimple() has more code to run. If there were no synchronization context before await (the case here - in console application) - the part after await will be executed on available thread pool thread. Since thread 3 has finished execution of its task - it is available and is capable to continue execution of the rest of TestAsyncSimple() and Main() functions, which it does. Thread 1 all this time is blocked as said above - so it cannot process any continuations (it's busy). In addition it's also not a thread pool thread (but that is not relevent here).
After you reached Console.ReadKey and pressed a key - Main task finally completes, thread 1 (waiting for this task to complete) is unblocked, then it returns from real Main function and process is terminated (only at this point thread 1 is "destroyed").
This question already has answers here:
Calling TaskCompletionSource.SetResult in a non blocking manner
(4 answers)
Closed 5 years ago.
I'm facing a deadlock-issue in a piece of code of mine. Thankfully, I've been able to reproduce the problem in the below example. Run as a normal .Net Core 2.0 Console application.
class Class2
{
static void Main(string[] args)
{
Task.Run(MainAsync);
Console.WriteLine("Press any key...");
Console.ReadKey();
}
static async Task MainAsync()
{
await StartAsync();
//await Task.Delay(1); //a little delay makes it working
Stop();
}
static async Task StartAsync()
{
var tcs = new TaskCompletionSource<object>();
StartCore(tcs);
await tcs.Task;
}
static void StartCore(TaskCompletionSource<object> tcs)
{
_cts = new CancellationTokenSource();
_thread = new Thread(Worker);
_thread.Start(tcs);
}
static Thread _thread;
static CancellationTokenSource _cts;
static void Worker(object state)
{
Console.WriteLine("entering worker");
Thread.Sleep(100); //some work
var tcs = (TaskCompletionSource<object>)state;
tcs.SetResult(null);
Console.WriteLine("entering loop");
while (_cts.IsCancellationRequested == false)
{
Thread.Sleep(100); //some work
}
Console.WriteLine("exiting worker");
}
static void Stop()
{
Console.WriteLine("entering stop");
_cts.Cancel();
_thread.Join();
Console.WriteLine("exiting stop");
}
}
What I'd expect is the complete sequence as follows:
Press any key...
entering worker
entering loop
entering stop
exiting worker
exiting stop
However, the actual sequence stalls on the Thread.Join call:
Press any key...
entering worker
entering stop
Finally, if I insert a small delay in the MainAsync body, everything goes fine.
Why (where) the deadlock happens?
NOTE: in the original code I solved using a SemaphoreSlim instead of a TaskCompletionSource, and there's no problems at all. I only would like to understand where the problem is.
tcs.SetResult(null); call in Worker() will not return until the underlying task is finished (check this question for details). In you case the task status is WaitingForActivation that's why you get a deadlock:
Thread executing Worker() is blocked by tcs.SetResult(null) call.
Thread executing Stop() is blocked by _thread.Join() call.
Because MainAsync() thread is 'faster' than the other thread.
And you're doing control only on tasks not on threads!
In your method MainAsync() you await method StartAsync() to finish its work and then you start the thread. Once method StartAsync() is done with its work (created and started thread) that function informs MainAsync() about finishing its work. Then MainAsync() calls Stop method.
But where is your thread? It runs in parallel without any control and tries to finish its work. This isn't deadlock, there is no synchronization between task and thread.
Thats why when you put await Task.Delay(1) your code works because thread is enough fast to finish work before task end it (thread.join).
What's the difference between these two approaches:
public static int Main(string[] args)
{
string result;
Task.Run(async () =>
{
Task<string> getStringTask = GetStringAsync();
result = await validationsTask;
}).Wait();
Console.WriteLine(result);
}
and
public static int Main(string[] args)
{
Task<string> getStringTask = GetStringAsync();
getStringTask.Wait();
string result = getStringTask.Result;
Console.WriteLine(result);
}
I've seen a lot of people using the first approach and I'm not sure why. Is there any particular advantage? Which one is recommended for waiting async methods inside main of a Console Application?
Is there any particular advantage?
Usually with async methods the operation is initialized synchronously and then the wait can be asynchronous with await or syncrhnous with Wait(). The Main method can't be async so you are force to block with Wait() there or you can do a Console.ReadKey() to run until the user presses a key.
Task.Run(async () => ... ) can be quite useful when the async operation is expensive to initialize. That way you allow the main thread to continue while the operation is initializing.
Which one is recommended for waiting async methods inside main of a Console Application?
I would use a slightly modified version of the second approach. You can add a MainAsync method and call that from Main then you can use await inside it.
public static async Task MainAsync()
{
string result = await GetStringAsync();
Console.WriteLine(result);
}
public static int Main(string[] args)
{
MainAsync().Wait();
}
Also with console apps there is no risk of deadlock as there is no SynchronizationContext and the default thread pool one gets used.
The first approach continues execution after the asynch function is finished using a thread pool thread while the second approach continues execution using the calling thread that starts the asynch function.
With the second approach, there is a possibility of deadlocks. For example (similar to an example extracted from the book CLR via C#):
public static int Main(string[] args)
{
Task<string> getStringTask = GetStringAsync();
string result = getStringTask.Result; //the main thread is blocked waiting.
Console.WriteLine(result);
}
public Task<string> GetStringAsync()
{
// Issue the HTTP request and let the thread return from GetHttp
HttpResponseMessage msg = await new HttpClient().GetAsync("http://Wintellect.com/");
// We never get here: The main thread is waiting for this method to finish but this method
// can't finish because the main thread is waiting for it to finish --> DEADLOCK!
return await msg.Content.ReadAsStringAsync();
}
So the first approach avoids this problem:
public static int Main(string[] args)
{
string result;
Task.Run(async () =>
{
// We run on a thread pool thread
Task<string> getStringTask = GetStringAsync();
// We do get here because any thread pool thread can execute this code, we don't need the main thread.
result = await validationsTask;
}).Wait();
Console.WriteLine(result);
}
Another solution is using ConfigureAwait(false), extracted from the book:
Passing true to this method gives you the same behavior as not calling
the method at all. But, if you pass false, the await operator does
not query the calling thread’s SynchronizationContext object and, when
a thread pool thread completes theTask, it simply completes it and the
code after the await operator executes via the thread pool thread.
public Task<string> GetStringAsync()
{
HttpResponseMessage msg = await new HttpClient().GetAsync("http://Wintellect.com/").ConfigureAwait(false);
// We DO get here now because a thread pool can execute this code
// as opposed to forcing the main thread to execute it.
return await msg.Content.ReadAsStringAsync().ConfigureAwait(false);
}
I'm trying to get my head around await and async so I wrote this little test app, but what I expected does not happen.
Instead of waiting for the task to complete, the program continues to execute.
class Program
{
static void Main(string[] args)
{
var task = new Task(Run);
task.Start();
task.Wait();
Console.WriteLine("Main finished");
Console.ReadLine();
}
public async static void Run()
{
var task = Task.Factory.StartNew(() =>
{
Console.WriteLine("Starting");
Thread.Sleep(1000);
Console.WriteLine("End");
});
await task;
Console.WriteLine("Run finished");
}
}
Output
Main finished
Starting
End
Run finished
If I swap the 'await task' for 'task.Await()' it then runs as I would have expected producing
Starting
End
Run finished
Main finished
That is because when you have asynchronous void method, there is nothing you can do to track it's completion. Yours new Task(Run) only creates a task for starting the Run method. After the Run arrives at first await, there is nothing tracking the progress of the method, because there is nothing associated with the progress of the method. To fix it, you have to return Task instead of void and await that, instead of creating new Task.
Difference between async void and async Task is described here.
I have some code that creates a task that does some slow work like this:
public static Task wait1()
{
return new Task(() =>
{
Console.WriteLine("Waiting...");
Thread.Sleep(10000);
Console.WriteLine("Done!");
});
}
In the real implementation, the Thread.Sleep will actually be a web service call. I would like to change the body of the method can use await (so it does not consume a thread during the network access/sleep). My first attempt (based on shotgun-debugging the compile errors) was this:
public static Task wait2()
{
return new Task(async () =>
{
Console.WriteLine("Waiting...");
await Task.Delay(10000);
Console.WriteLine("Done!");
});
}
However; this task doesn't seem to behave the same as the first one, because when I call .Wait() on it; it returns immediately.
Below is a full sample (console app) showing the differences (the app will end immediately when the second task starts).
What do I need to do so that I can call Start and Wait on a Task which happens to have code using await inside it? The tasks are queued and executed later by an agent, so it's vital that the task is not auto-started.
class Program
{
static void Main(string[] args)
{
var w1 = wait1();
w1.Start();
w1.Wait(); // This waits 110 seconds
var w2 = wait2();
w2.Start();
w2.Wait(); // This returns immediately
}
public static Task wait1()
{
return new Task(() =>
{
Console.WriteLine("Waiting...");
Thread.Sleep(10000);
Console.WriteLine("Done!");
});
}
public static Task wait2()
{
return new Task(async () =>
{
Console.WriteLine("Waiting...");
await Task.Delay(10000);
Console.WriteLine("Done!");
});
}
}
It seems like this isn't possible! See alexm's answer here:
Tasks returned by async methods are always hot i.e. they are created in Running state.
:-(
I've worked around this by making my agent queue Func<Task>s instead, and the overload that receives a task simply queues () => task. Then; when de-queing a task, I check if it's not running, and if so, start it:
var currentTask = currentTaskFunction();
if (currentTask.Status == TaskStatus.Created)
currentTask.Start();
It seems a little clunky to have to do this (if this simple workaround works; why the original restriction on async methods always being created hot?), but it seems to work for me :-)
You could write this as:
public static async Task Wait2()
{
Console.WriteLine("Waiting...");
await Task.Delay(10000);
Console.WriteLine("Done!");
}
In general, it's rarely a good idea to ever use new Task or new Task<T>. If you must launch a task using the ThreadPool instead of using the async/await language support to compose one, you should use Task.Run to start the task. This will schedule the task to run (which is important, tasks should always be "hot" by conventions).
Note that doing this will make it so you don't have to call Task.Start, as well.
To help you understand this realize that async / await essentially does not create a new thread but rather it schedules that portion of code to be ran at an available point in time.
When you create the new Task(async () => ...) you have a task that run an async method. When that inner async method hits an await the 'new Task' is considered complete because the rest of it has been scheduled. To help you understand better place some code (a lot if wanted) in the 'new Task' before the await command. It will all execute before the application terminates and once await is reached that task will believe it has completed. It then returns and exits the application.
The best way to avoid this is to not place any task or async methods inside of your task.
Remove the async keyword and the await keyword from the method and it will work as expected.
This is the same as creating a callback if you're familiar with that.
void MethodAsync(Action callback)
{
//...some code
callback?.Invoke();
}
//using this looks like this.
MethodAsync(() => { /*code to run when complete */});
//This is the same as
Task MethodAsync()
{
//... some code here
}
//using it
await MethodAsync();
/*code to run when complete */
The thing to understand is that you're creating a new task within a task basically. So the inner 'callback' is being created at the await keyword.
You're code looks like this..
void MethodAsync(Action callback)
{
//some code to run
callback?.Invoke(); // <- this is the await keyword
//more code to run.. which happens after we run whoever is
//waiting on callback
}
There's code missing obviously. If this doesn't make sense please feel free to contact me and I'll assist. async / await (meant to make things simpler) is a beast to wrap your head around at first. Afterward you get it then it'll probably be your favorite thing in c# since linq. :P
Try this:
public async static Task wait2()
{
Console.WriteLine("Waiting...");
await Task.Delay(2000);
Console.WriteLine("Done!");
}
But we aware that the task is already started so you don't have to call start:
var w2 = wait2();
//w2.Start();
w2.Wait();
I think the problem with your wait2 function is that is creating 2 task, the one in new Task(...) and another in Task.Delay(). You are waiting for the first one, but you are not waiting for the inner one.