I have a simple code where I'm trying to get a better understanding of how a method can be called asynchronously in C#.
I have a function called Function1 which I want to run asynchronously
static void Function1(out int threadId)
{
Console.WriteLine("I'm inside Function 1. Going to sleep for 7 seconds...");
Thread.Sleep(7000);
Console.WriteLine("I'm awake now");
threadId = Thread.CurrentThread.ManagedThreadId;
}
Then I have a second function Function2 which I want to run normally (synchronously)
static void Function2()
{
Thread.Sleep(3000);
Console.WriteLine("I'm inside Function 2");
}
I also created a delegate with the same method signature as Function1
delegate void AsyncMethodCaller(out int threadId);
And here is my main calling method:
static void Main(string[] args)
{
int threadId;
AsyncMethodCaller caller = new AsyncMethodCaller(Function1);
caller.BeginInvoke(out threadId, null, null);
Function2();
}
In my main method, I expect Function1 to start running asynchronously; and then without waiting on it to finish, Function2 executes. So I expect the following output:
I'm inside the asynchronous Function 1. Going to sleep for 7
seconds... I'm inside Function 2 I'm awake now
Instead I just get the following output:
I'm inside the asynchronous Function 1. Going to sleep for 7
seconds... I'm inside Function 2
Why is my expectation different from reality? why is the "I'm awake now" line never reached?
Thank you
The basic process lifetime rules for .NET are that a process exits when all foreground threads have exited. Any background threads are simply aborted; the process will not wait for them.
Furthermore, when you call a delegate's BeginInvoke() method, this implicitly causes the delegate to be invoked using the thread pool. The thread pool is made entirely of background threads.
In other words, when you call BeginInvoke(), you are telling .NET to invoke the delegate using a thread that does not in and of itself guarantee its own lifetime. That thread can (and in this case, is) aborted once the single main foreground thread of the process exits, which occurs immediately after you call Function2().
If you want the asynchronously invoked delegate to complete normally, you'll have to wait for it explicitly. E.g.:
IAsyncResult result = caller.BeginInvoke(out threadId, null, null);
Function2();
caller.EndInvoke(out threadId, result);
The EndInvoke() method will block until the asynchronously invoked delegate has completed, allowing the main thread to wait for that to happen and thus ensuring that the thread used to invoke the delegate is not aborted before the invocation has completed.
The structure of your code example suggests you've already looked at MSDN's Calling Synchronous Methods Asynchronously, but in case you haven't I'll mention that page, as it includes a lot of details that would help explain how to deal with this particular scenario.
Related
Output for the below code is
A
B
C
Since the root call FirstCall() doesn't await, I would have expected the Task.Delay to not actually wait since the Task that is returned by the ChildCall bubbles up and is never waited.
Can someone explain why Task.Delay actually awaits when the root caller is not awaited?
Specifically, when FirstCall reaches the await statement inside it (await ChildCall()) the execution of the method is suspended and control returns to the Main method. Here FirstCall is not awaited - what is preventing it from then going ahead and executing Console.ReadLine()
private static void Main(string[] args)
{
FirstCall();
Console.ReadLine();
}
private static async Task FirstCall()
{
await ChildCall();
Console.WriteLine("C");
}
private static async Task ChildCall()
{
Console.WriteLine("A");
await Task.Delay(TimeSpan.FromSeconds(5));
Console.WriteLine("B");
}
When you don't await, you only continue the thread you are in.
If you write:
private static void Main(string[] args)
{
FirstCall();
Console.WriteLine("D");
Console.ReadLine();
}
Your output will look something like:
D
A
B
C
or
A
D
B
C
Skipping await doesn't disable the other awaits. When calling an async task, you can think of it as creating a new Thread that does it's own thing. When you call await you are simply saying to the current thread, don't do anything until that one is done.
But the second thread can still call await a third thread, and tell itself to await or wait until the third thread is done. The first thread, if not awaited will just continue and close the program before the other threads finish.
You can test this by removing the Console.Readline() and instead write out Main Thread Completed
EDIT: ADDITIONAL
To your specific Quesiton:
Specifically, when FirstCall reaches the await statement inside it (await ChildCall()) the execution of the method is suspended and control returns to the Main method. Here FirstCall is not awaited - what is preventing it from then going ahead and executing Console.ReadLine()
The execution of the method is NOT suspended as you thought. See the example below of your edited code:
private static void Main(string[] args)
{
FirstCall();
Console.WriteLine("Main Thread Finished...");
var word = Console.ReadLine();
Console.WriteLine("Printed: " + word);
Console.ReadLine();
}
In the image below, the left hand side I immediately Typed test. On the right hand side I waited for the child threads to complete:
So to answer your other question:
So you are saying each child method has its own state machine that is honoured irrespective of what its parent is doing?
Partially...
To answer correctly you need to know the difference between a Task and a Thread.
Task vs Thread
In short a Task uses a Thread Pool and a Thread uses a dedicated Thread. Think of a dedicated Thread as starting a secondary Main(args) function. Where as a Thread pool uses a parent-child-treelike structure (Could be wrong on this) to keep track of what threads are executing.
What this means practically
Both Tasks and Threads have complete internal states that is honoured irrespective of what its parent | EXCEPT When the Parent of a Task is completed, all the Children Tasks Stop *Immediately.
Tasks have Return Types where as Threads don't.
For a program to stop - you have to stop all threads but you only have to stop the parent Task to stop the program.
In book Microsoft Visual C # Step by Step Ninth Edition John Sharp said:
You can also register a callback method (in the form of an Action
delegate) with the cancellation token by using the Register method.
When an application invokes the Cancel method of the corresponding
CancellationTokenSource object, this callback runs. However, you
cannot guarantee when this method executes; it might be before or
after the tasks have performed their own cancellation processing, or
even during that process.
cancellationToken.Register(doAdditionalWork);
private void doAdditionalWork() { // Perform additional cancellation
processing }
It's all.
First question.
I do not understand how this can be. Can someone give an example when a method is registered, the token is canceled, but for some reason the method that is registered has not been executed?
Second question.
The order of method calls. It is reverse. Why? Inside a stack of delegates??
using System;
using System.Threading;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
void MyMethod(int a)
{
Console.WriteLine(a);
}
CancellationTokenSource MyCancellationTokenSource = new CancellationTokenSource();
CancellationToken MyCancellationToken = MyCancellationTokenSource.Token;
MyCancellationToken.Register(() => MyMethod(1));
MyCancellationToken.Register(() => MyMethod(2));
MyCancellationToken.Register(() => MyMethod(3));
MyCancellationTokenSource.Cancel();
//Console:
//3
//2
//1
}
}
}
Keep in mind that execution order in multi threaded systems is not well defined. A thread may be suspended at any time for theoretically any length of time. Ordering is only guaranteed within a thread. For example the following could happen
Cancel is called on thread A
MyMethod is queued to run (thread A)
Cancel token is marked as canceled (thread A)
The task checks the token, observes that it is cancelled, and aborts (thread B)
Scheduler gets around to calling MyMethod on thread C
It is unclear to me if there are any case where MyMethod would never run. The documentation for CancellationToken.Register states:
Registers a delegate that will be called when this CancellationToken is canceled.
and
If this token is already in the canceled state, the delegate will be run immediately and synchronously.
So I would assume that the registered method will always be called if the token is, or will be, canceled. But you cannot assume anything about when this it is done.
I'm working with an unmanaged library that mandates that all calls to its API is run on the same thread. We want to use the Reactive extensions's EventLoopScheduler to facilitate that since we'll be using Observable for other things.
I'm using a method similar to the Run method in the code sample below to execute code in the scheduler which will always run on the same thread. When I'm working with managed code this works as expected and all calls are run on the thread managed by the event loop and before / after the async call is the main thread.
But, when I call a P/Invoke (the one in the code sample is just an example, I'm not really calling this one in my code but the behavior is the same), the thread does run on the event loop thread, but so does everything after!
I've tried adding ConfigureAwait(true) (and false) but it doesn't change anything. I'm really confused by this behavior, why would calling a P/Invoke change the thread continuing after the await !!?
Here's the code to reproduce:
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern int MessageBox(IntPtr hWnd, string lpText, string lpCaption, uint uType);
public static Task Run(Action action, IScheduler scheduler)
{
return Observable.Start(action, scheduler).SingleAsync().ToTask();
}
public static string ThreadInfo() =>
$"\"{Thread.CurrentThread.Name}\" ({Thread.CurrentThread.ManagedThreadId})";
private static async Task Main(string[] args)
{
var scheduler = new EventLoopScheduler();
Console.WriteLine($"Before managed call on thread {ThreadInfo()}");
await Run(() => Console.WriteLine($"Managed call on thread {ThreadInfo()}"), scheduler);
Console.WriteLine($"After managed call on thread {ThreadInfo()}");
Console.WriteLine($"Before PInvoke on thread {ThreadInfo()}");
await Run(() => MessageBox(IntPtr.Zero, $"Running on thread {ThreadInfo()}", "Attention", 0), scheduler);
Console.WriteLine($"After PInvoke on thread {ThreadInfo()}");
}
The execution returns something like this:
Before managed call on thread "" (1)
Managed call on thread "Event Loop 1" (6)
After managed call on thread "" (1)
Before PInvoke on thread "" (1)
Message box displayed with text: Running on thread "Event Loop 1" (6)
After PInvoke on thread "Event Loop 1" (6)
Where I expected
Before managed call on thread "" (1)
Managed call on thread "Event Loop 1" (6)
After managed call on thread "" (1)
Before PInvoke on thread "" (1)
Message box displayed with text: Running on thread "Event Loop 1" (6)
After PInvoke on thread "" (1)
Tasks
A Task or a promise is a just an abstraction for callbacks. And async/await is just syntactic sugar for tasks.
Since it's a callback abstraction, await doesn't block the thread.
Why does it look like it's blocking? That's because await rewrites your code into a state-machine which advances through its states when the Task being awaited completes.
It roughly gets rewritten like this:
switch (state)
{
case 0:
Console.WriteLine($"Before managed call on thread {ThreadInfo()}");
Await(Run(() => Console.WriteLine($"Managed call on thread {ThreadInfo()}"), scheduler));
return;
case 1:
Console.WriteLine($"After managed call on thread {ThreadInfo()}");
Console.WriteLine($"Before PInvoke on thread {ThreadInfo()}");
Await(Run(() => MessageBox(IntPtr.Zero, $"Running on thread {ThreadInfo()}", "Attention", 0), scheduler));
return;
case 2:
Console.WriteLine($"After PInvoke on thread {ThreadInfo()}");
return;
}
The actual rewrite uses goto rather than a switch, but the concept is the same. So when a task completes, it call this state-machine with state += 1 - in the same threading context. You only see task pool threads when you use a task scheduler.
Leaks in the abstraction
The explanation for why you see this particular behavior:
After managed call on thread "" (1)
is quite complicated. It has to do with whether a scheduled thunk completes immediately or not. If you add a Thread.Sleep in the first managed call, you'll notice that the continuation runs on the event loop thread.
This is due to scheduling optimizations preferring to only queue if something is currently running. When you call ToTask(), you're using the default scheduler, which is the current thread scheduler.
The current thread scheduler works like this:
Free? Run immediately.
Busy? Queue the work.
The run immediately behavior is why you see the log running on the main thread.
If you just add a
var scheduler = new EventLoopScheduler();
scheduler.Schedule(() => Thread.Sleep(1000));
to the very beginning, you make the event loop busy, causing everything to go into queuing, so you then see everything logs in the event loop thread. So this has nothing to do with P/Invoke.
To be clear, this isn't about the schedulers being specified for observing, but subscribing. When you convert Observables into other abstractions like Tasks, Enumerables, Blocking Joins etc., some internal complexity may leak through.
I have two methods, MethodA & MethodB. MethodB has to run on the UI thread. I need them to run one after the other without allowing MethodC to run between them.
MethodC is called when a user clicks on a lovely little button.
What I did to ensure this is put a Lock around the code thus:
lock (MyLock)
{
MethodA(param1, param2);
MyDelegate del = new MyDelegate(MethodB);
if (this.IsHandleCreated) this.Invoke(del);
}
And for MethodC:
public void MethodC()
lock (MyLock)
{
Do bewildering stuff.....
}
Problem is I'm getting stuck. It looks like my code's going into a deadlock.
When I look at the threads I see that the code called by the button click is stuck at lock (MyLock) in MethodC and my other thread seems stuck at this.Invoke(del).
I've read it's dangerous to invoke a method from within a Lock but since I'm the one who wrote the code there and this seems to happen even with just a Thread.Sleep I figure it's not the code that's getting me into trouble.
Why would the the Invoked method stop working?
Is it possibly waiting for the lock on methodC to be released before going back to the original lock it was invoked from?
So, imagine the following situation:
Your background thread starts running the code. It grabs the lock and then starts running MethodA.
MethodC is called while MethodA is in the middle of its work. MethodA waits for the lock to be free, blocking the UI thread until that happens.
The background thread finishes MethodA and goes to invoke MethodB on the UI thread. MethodB can't run until all previous items in the message pump's queue have finished.
MethodC is at the top of the message pump's queue, waiting until MethodB finishes, and MethodB is in the queue waiting until MethodC finishes. They are both waiting on each other, which is a deadlock.
So, how do you resolve this issue? What you really need is some way of "waiting" on a lock without actually blocking the thread. Fortunately (in .NET 4.5) this is easy to do thanks to the Task Parallel Library. (I have waiting in quotes because we don't actually want to wait, we just want to execute MethodC as soon as the lock is freed without actually waiting/blocking the current thread.)
Instead of using an object for MyLock use:
private static SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);
Now for MethodC you can do:
public async Task MethodC() //you can change the signature to return `void` if this is an event handler
{
try
{
await semaphore.WaitAsync();
//Do stuff
}
finally
{
semaphore.Release();
}
}
The key here is that because we await a task that represents when the semaphore is actually free we aren't blocking the current thread, which will allow the other background task to marshal MethodB to the UI thread, finish the method, release the semaphore, and then let this method execute.
Your other code doesn't need to (but still can, if you want) use async waiting on the semaphore; blocking the background thread isn't nearly as much of a problem, so the only key change there is using the semaphore instead of lock:
public void Bar()
{
try
{
semaphore.Wait();
MethodA(param1, param2);
MyDelegate del = new MyDelegate(MethodB);
if (this.IsHandleCreated) this.Invoke(del);
}
finally
{
semaphore.Release();
}
}
Assuming your MethodA also contains something like:
lock(MyLock) {
}
You are absolutely correct, you've got a dead lock. MethodA cannot obtain a lock on MyLock because it was already locked before the method was entered.
You can rather try this:
Lock (MyLock)
{
MethodA(param1, param2);
MyDelegate del = new MyDelegate(MethodB);
MyDelegate del2 = new MyDelegate(MethodC);
MyDelegate del3 = del+del2
if (this.IsHandleCreated) this.Invoke(del3);
}
You confused a hell out of people using lock. This task has nothing to do with multi-threading per se.
Simple usability solution is what you need - disable your lovely little button until you are ready to run MethodC.
I have requirement to cancel method execution if it takes the more than two seconds to complete and restart it on another thread.
So, is there any way/call back mechanism/HACK, I can make method inform me that it crossed 2 seconds time limit?
check if network drive exists with timeout in c#
https://web.archive.org/web/20140222210133/http://kossovsky.net/index.php/2009/07/csharp-how-to-limit-method-execution-time
Async Pattern:
public static T SafeLimex<T>(Func<T> F, int Timeout, out bool Completed)
{
var iar = F.BeginInvoke(null, new object());
if (iar.AsyncWaitHandle.WaitOne(Timeout))
{
Completed = true;
return F.EndInvoke(iar);
}
F.EndInvoke(iar); //not calling EndInvoke will result in a memory leak
Completed = false;
return default(T);
}
You should create System.Threading.Timer on two seconds, and run your method in another thread and wait for callback from it, if method completes before timer runs you should dispose timer, otherwise you should abort thread in which you method are executing. This is pretty simple for example
using (new Timer(BreakFunction, true, TimeSpan.FromMinutes(2), Timeout.Infinite))
{
//TODO:here you should create another thread that will run your method
}
In BreakFunction you should abort thread that runs your methods
It would be good if you can find it. I've been looking for it too.
What I usually do is start the method in another Thread, and start a Timer with 2 seconds in this case. The first time it raises the event, just do:
if (a.IsAlive)
{
a.Abort();
}
Two important things:
The Thread declared should be visible by the method that handles the timer
When calling Abort(), it raises ThreadAbortException, so you should correctly handle it in the method.