I am playing with the async/await in the C# and while I think that I understand most of the concepts, I can not explain why the code line "var rxres = await ..." first time runs on my UDP thread, and after further receptions of the packets runs on the worker thread. As far as I understand, I am not "yielding" back to the thread function and it is still alive and so all invocations of ReceiveAsync should run on the thread I created.
static void Main(string[] args)
{
var ewh = new EventWaitHandle(false, EventResetMode.ManualReset);
var udpThread = new Thread(async () =>
{
ListenUdpAsync().Wait();
});
udpThread.Name = "UDP THREAD";
udpThread.Start();
ewh.WaitOne();
}
static public async Task ListenUdpAsync()
{
var localPort = 5555;
var localBind = new IPEndPoint(IPAddress.Any, localPort);
using (var udpc = new UdpClient(localBind))
{
while(true)
{
var rxres = await udpc.ReceiveAsync();
Console.WriteLine("Rx From: " + rxres.RemoteEndPoint);
Console.WriteLine("Rx Data: " + Encoding.ASCII.GetString(rxres.Buffer));
}
}
}
I am not "yielding" back to the thread function
The method yields once hitting await udpc.ReceiveAsync(), that is how async-await works. ListenAsync itself synchronously blocks, but since there is no sync context that comes into play, the continuation is able to marshal itself onto an arbitrary thread pool thread.
so all invocations of ReceiveAsync should run on the thread I created.
Not really. Generally, when you're running inside a console application, it uses the default TaskScheduler, which internally uses the thread pool to execute continuations on an arbitrary threadpool thread. Ones ReceiveAsync() completes, its continuation needs to be scheduled somewhere, and that place is on the thread pool.
On a side note - there is no reason to use the async modifier on the delegate, as you're not awaiting anything inside, but synchronously blocking.
Related
I recently came across some code which confused me heavily, I have always thought that you must use threads or Async tasks, not mix and match between them,
public async Task DoWork()
{
Task.Delay(1000);
}
Now I saw code calling this like so:
public void Main()
{
var thread = new Thread(async () => { await DoWorkAync(); })
{
Priority = ThreadPriority.Highest,
IsBackground = true
};
// Start thread
proccessThread.Start();
}
Now this magically seemed to NOT create a thread each time it was run, it seemed to be using the ThreadPool.
now what I am struggling to understand is the difference between the above and:
public void Main()
{
var task = Task.Run(DoWorkASync);
}
From my testing, it seems that C# Thread has a different functionality when passing in an Async Expression vs the standard method on which to run>
This construct:
var thread = new Thread(async () => { await DoWorkAync(); });
// Start thread
proccessThread.Start();
Calls Thread constructor overload accepting ThreadStart delegate, and ThreadStart delegate is () => void. So you have this:
var thread = new Thread(StuffYourThreadExecutes);
thread.Start();
static async void StuffYourThreadExecutes() {
await DoWorkAsync();
}
So you start new thread and it runs the code until first asynchronous operation begins. Then thread exists. After that first asynchronous operation completes - the rest executes on whatever thread task scheduler providers (usually thread pool thread). Any exceptions which happen during this process cannot be observed.
For example if DoWorkAsync is something like:
static async Task DoWorkAsync(){
await Task.Delay(1000);
}
Then thread starts and almost immediately exits, doing nothing useful.
Task.Run, when passing async delegate there, does what is stated in docs:
Queues the specified work to run on the thread pool and returns a
proxy for the task
So whole operation just runs on thread pool thread without creating threads for nothing. You can observe exceptions by awaiting task returned by Task.Run.
I am in a situation where I have to spawn a new thread manually, so I am able to can call .SetApartmentState(ApartmentState.STA). This means (as far as I know) that I cannot use Task. But I would like to know when the thread was done running, something like the await which works with async. However, the best I can come up with is a loop, constantly checking Thread.IsAlive, like this:
var thread = new Thread(() =>
{
// my code here
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
while(thread.IsAlive)
{
// Wait 100 ms
Thread.Sleep(100);
}
This should work (as long as the thread don't end up stalling), but it seems kind of clumsy. Isn't there a more clever way to check when the thread is done (or dead)?
It is only to avoid blocking the GUI thread, so any minor performance hits are fine (like some hundred milliseconds).
Here is an extension method you could use to enable the awaiting of threads (inspired from this article: await anything).
public static TaskAwaiter GetAwaiter(this Thread thread)
{
return Task.Run(async () =>
{
while (thread.IsAlive)
{
await Task.Delay(100).ConfigureAwait(false);
}
}).GetAwaiter();
}
Usage example:
var thread = new Thread(() =>
{
Thread.Sleep(1000); // Simulate some background work
});
thread.IsBackground = true;
thread.Start();
await thread; // Wait asynchronously until the thread is completed
thread.Join(); // If you want to be extra sure that the thread has finished
Could you use the BackgroundWorker class? It has an event that reports when its finished.
I am working on a data acquisition application and I want to ensure that it exits gracefully. That is, it processes all the already collected data, flushes all the (file) buffers to "disk" (persistent memory) and might even uploads the data to the cloud.
So, I wrote (based on this answer) the code below to catch every close event. (It is just a test code.)
Problem: If I use the X in the top-right corner of the console, the program gets terminated after a short delay, even though the termination sequence is still running. (The handler does get called, and it does start to wait for the threads to join but then it gets killed after a while.) If I terminate with Crt+C or Ctr+Break it works as intended; The termination sequence finishes and exits the process.
Question: How can I make the OS wait for my application to terminate instead of killing it off after a short grace period?
#region Trap application termination
[DllImport("Kernel32")]
private static extern bool SetConsoleCtrlHandler(EventHandler handler, bool add);
private delegate bool EventHandler(CtrlType sig);
static EventHandler _handler;
enum CtrlType
{
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT = 1,
CTRL_CLOSE_EVENT = 2,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT = 6
}
private static bool Handler(CtrlType sig, List<Thread> threads, List<Task> tasks, CancellationTokenSource cancellationRequest)
{
//starts new foregeound thread, so the process doesn't terminate when all the cancelled threads end
Thread closer = new Thread(() => terminationSequence(threads, tasks, cancellationRequest));
closer.IsBackground = false;
closer.Start();
closer.Join(); //wait for the termination sequence to finish
return true; //just to be pretty; this never runs (obviously)
}
private static void terminationSequence(List<Thread> threads, List<Task> tasks, CancellationTokenSource cancellationRequest)
{
cancellationRequest.Cancel(); //sends cancellation requests to all threads and tasks
//wait for all the tasks to meet the cancellation request
foreach (Task task in tasks)
{
task.Wait();
}
//wait for all the treads to meet the cancellation request
foreach (Thread thread in threads)
{
thread.Join();
}
/*maybe do some additional work*/
//simulate work being done
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
Console.WriteLine("Spinning");
while (stopwatch.Elapsed.Seconds < 30)
{
if (stopwatch.Elapsed.Seconds % 2 == 0)
{
Console.Clear();
Console.WriteLine("Elapsed Time: {0}m {1}s", stopwatch.Elapsed.Minutes, stopwatch.Elapsed.Seconds);
}
Thread.SpinWait(10000);
}
Environment.Exit(0); //exit the process
}
#endregion
static void Main(string[] args)
{
CancellationTokenSource cancellationRequest = new CancellationTokenSource(); //cancellation signal to all threads and tasks
List<Thread> threads = new List<Thread>(); //list of threads
//specifys termination handler
_handler += new EventHandler((type) => Handler(type, threads, new List<Task>(), cancellationRequest));
SetConsoleCtrlHandler(_handler, true);
//creating a new thread
Thread t = new Thread(() => logic(cancellationRequest.Token));
threads.Add(t);
t.Start();
}
Since C# 7.1 you can have an async Task Main() method. Using this, you can modify your handler to create a method, and wait on it in the Main method.
Sidenote: you should use tasks instead of threads wherever you can. Tasks manage your thread better, and they run of the ThreadPool. When you create a new Thread instance, it's assuming it'll be a long running task, and the windows will treat it differently.
So with that in mind, consider wrapping the TerminateSequence method in a task, instead of a thread, and make that task a member of your class. Now you won't have to wait for it in the context of the handler, you could instead wait for it in the Main method.
With the rest of your code remaining the same, you could do the following:
private Task _finalTask;
private static bool Handler(CtrlType sig, List<Thread> threads, List<Task> tasks, CancellationTokenSource cancellationRequest)
{
//starts new foregeound thread, so the process doesn't terminate when all the cancelled threads end
_finalTask = Task.Run(() => terminationSequence(threads, tasks, cancellationRequest));
}
// ...
static async Task Main(string[] args)
{
// ...
// Wait for the termination process
if(_finalProcess != null)
await _finalTask
}
If you're not working with C# 7.1 you can still do this, it'll just be a little less elegant. All you need to do is wait for it:
_finalTask?.Wait();
And that should do it.
How can I check if a thread returned to the thread pool, using VS C# 2015 debugger?
What's problematic in my case is the fact that it cannot be detected by debugging line by line.
async Task foo()
{
int y = 0;
await Task.Delay(5);
// (1) thread 2000 returns to thread pool here...
while (y<5) y++;
}
async Task testAsync()
{
Task task = foo();
// (2) ... and here thread 2000 is back from the thread pool, to run the code below. I want
// to confirm that it was in the thread pool in the meantime, using debugger.
int i = 0;
while (i < 100)
{
Console.WriteLine("Async 1 before: " + i++);
}
await task;
}
In the first line of testAsync running on thread 2000, foo is called. Once it encounters await Task.Delay(5), thread 2000 returns to thread pool (allegedly, I'm trying to confirm this), and the method waits for Task.Delay(5) to complete. In the meantime, the control returns to the caller and the first loop of testAsync is executed on thread 2000 as well.
So between two consecutive lines of code, the thread returned to thread pool and came back from there. How can I confirm this with debugger? Possibly with Threads debugger window?
To clarify a bit more what I'm asking: foo is running on thread 2000. There are two possible scenarios:
When it hits await Task.Delay(5), thread 2000 returns to the thread pool for a very short time, and the control returns to the caller, at line (2), which will execute on thread 2000 taken from the thread pool. If this is true, you can't detect it easily, because Thread 2000 was in the thread pool during time between two consecutive lines of code.
When it hits await Task.Delay(5), thread 2000 doesn't return to thread pool, but immediately executes code in testAsync starting from line (2)
I'd like to verify which one is really happening.
There is a major mistake in your assumption:
When it hits await Task.Delay(5), thread 2000 returns to the thread pool
Since you don't await foo() yet, when thread 2000 hits Task.Delay(5) it just creates a new Task and returns to testAsync() (to int i = 0;). It moves on to the while block, and only then you await task. At this point, if task is not completed yet, and assuming the rest of the code is awaited, thread 2000 will return to the thread pool. Otherwise, if task is already completed, it will synchronously continue from foo() (at while (y<5) y++;).
EDIT:
what if the main method called testAsync?
When synchronous method calls and waits async method, it must block the thread if the async method returns uncompleted Task:
void Main()
{
var task = foo();
task.Wait(); //Will block the thread if foo() is not completed.
}
Note that in the above case the thread is not returning to the thread pool - it is completely suspended by the OS.
Maybe you can give an example of how to call testAsync so that thread 2000 returns to the thread pool?
Assuming thread 2k is the main thread, it cannot return to the thread pool. But you can use Task.Run(()=> foo()) to run foo() on the thread pool, and since the calling thread is the main thread, another thread pool thread will pick up that Task. So the following code:
static void Main(string[] args)
{
Console.WriteLine("main started on thread {0}", Thread.CurrentThread.ManagedThreadId);
var testAsyncTask = Task.Run(() => testAsync());
testAsyncTask.Wait();
}
static async Task testAsync()
{
Console.WriteLine("testAsync started on thread {0}", Thread.CurrentThread.ManagedThreadId);
await Task.Delay(1000);
Console.WriteLine("testAsync continued on thread {0}", Thread.CurrentThread.ManagedThreadId);
}
Produced (on my PC) the following output:
main started on thread 1
testAsync started on thread 3
testAsync continued on thread 4
Press any key to continue . . .
Threads 3 and 4 came from and returned to the thread pool.
You can print out the Thread.CurrentThread.ManagedThreadId to the console. Note that the thread-pool is free to re-use that same thread to run continuations on it, so there's no guarantee that it'll be different:
void Main()
{
TestAsync().Wait();
}
public async Task FooAsync()
{
int y = 0;
await Task.Delay(5);
Console.WriteLine($"After awaiting in FooAsync:
{Thread.CurrentThread.ManagedThreadId }");
while (y < 5) y++;
}
public async Task TestAsync()
{
Console.WriteLine($"Before awaiting in TestAsync:
{Thread.CurrentThread.ManagedThreadId }");
Task task = foo();
int i = 0;
while (i < 100)
{
var x = i++;
}
await task;
Console.WriteLine($"After awaiting in TestAsync:
{Thread.CurrentThread.ManagedThreadId }");
}
Another thing you can check is ThreadPool.GetAvailableThreads to determine if another worker has been handed out for use:
async Task FooAsync()
{
int y = 0;
await Task.Delay(5);
Console.WriteLine("Thread-Pool threads after first await:");
int avaliableWorkers;
int avaliableIo;
ThreadPool.GetAvailableThreads(out avaliableWorkers, out avaliableIo);
Console.WriteLine($"Available Workers: { avaliableWorkers},
Available IO: { avaliableIo }");
while (y < 1000000000) y++;
}
async Task TestAsync()
{
int avaliableWorkers;
int avaliableIo;
ThreadPool.GetAvailableThreads(out avaliableWorkers, out avaliableIo);
Console.WriteLine("Thread-Pool threads before first await:");
Console.WriteLine($"Available Workers: { avaliableWorkers},
Available IO: { avaliableIo }");
Console.WriteLine("-------------------------------------------------------------");
Task task = FooAsync();
int i = 0;
while (i < 100)
{
var x = i++;
}
await task;
}
On my machine, this yields:
Thread-Pool threads before first await:
Available Workers: 1023, Available IO: 1000
----------------------------------------------
Thread-Pool threads after first await:
Available Workers: 1022, Available IO: 1000
I'd like to verify which one is really happening.
There is no way to "verify" that with debugger, because the debugger is made to simulate the logical (synchronous) flow - see Walkthrough: Using the Debugger with Async Methods.
In order to understand what is happening (FYI it's your case (2)), you need to learn how await works starting from Asynchronous Programming with Async and Await - What Happens in an Async Method section, Control Flow in Async Programs and many other sources.
Look at this snippet:
static void Main(string[] args)
{
Task.Run(() =>
{
// Initial thread pool thread
var t = testAsync();
t.Wait();
});
Console.ReadLine();
}
If we make the lambda to be async and use await t; instead of t.Wait();, this is the point where the initial thread will be returned to the thread pool. As I mentioned above, you cannot verify that with debugger. But look at the above code and think logically - we are blocking the initial thread, so if it' wasn't free, your testAsync and foo methods will not be able to resume. But they do, and this can easily be verified by putting breakpoint after await lines.
We have alot of requests in our system so we use Tasks with WebApi. On some places we have high requirements on speed so we cant wait for the Task to complete, I have created a Worker for this. It creates a nested container so that Entity frameworks DbContext wont get disposed etc. But it looks like Task.Run spawns a new thread for each time, how well will this scale?
public class BackgroundWorker<TScope> : IBusinessWorker<TScope>, IRegisteredObject where TScope : class
{
private readonly IBusinessScope<TScope> _scope;
private bool _started;
private bool _stopping;
public BackgroundWorker(IBusinessScope<TScope> scope)
{
_scope = scope;
}
public void Run(Func<TScope, Task> action)
{
if(_stopping) throw new Exception("App pool is recycling, cant queue work");
if(_started) throw new Exception("You cant call Run multiple times");
_started = true;
HostingEnvironment.RegisterObject(this);
Task.Run(() =>
action(_scope.EntryPoint).ContinueWith(t =>
{
_scope.Dispose();
HostingEnvironment.UnregisterObject(this);
}));
}
public void Stop(bool immediate)
{
_stopping = true;
if(immediate)
HostingEnvironment.UnregisterObject(this);
}
}
Used like
backgroundWorker.Run(async ctx => await ctx.AddRange(foos).Save());
If I google they all end up using Task.Run but doesn't that kill the purpose?
Update:
Did a test
var guid = Guid.NewGuid();
_businessWorker.Run(async ctx => {
System.Diagnostics.Debug.WriteLine("{0}: {1}", guid, Thread.CurrentThread.ManagedThreadId);
await Task.Delay(1);
System.Diagnostics.Debug.WriteLine("{0}: {1}", guid, Thread.CurrentThread.ManagedThreadId);
});
This outputs
3bdbe90b-c31e-4709-95d8-f7516210b0ac: 17
3bdbe90b-c31e-4709-95d8-f7516210b0ac: 9
6548fd26-d209-4427-9a91-40fc30aa509e: 15
6548fd26-d209-4427-9a91-40fc30aa509e: 19
7411b043-4fae-44bf-b93f-4273a532afa1: 7
7411b043-4fae-44bf-b93f-4273a532afa1: 17
Which indicates that Task.Run actually works like i think it should
With real DB code it looks like this
a939713d-d728-46c9-be33-aa57704cf242: 19 <--
a939713d-d728-46c9-be33-aa57704cf242: 19 <-- Used same for entire work
7e588a42-afd0-4ab5-ba6b-f8520c889cde: 7
7e588a42-afd0-4ab5-ba6b-f8520c889cde: 19 <-- Reused first works thread when work #2 continued
6f3b067f-f478-43f9-8411-8142b449c28b: 8
6f3b067f-f478-43f9-8411-8142b449c28b: 18
update:
Tried Luaan's approach, seems to work with Tasks spawned from EntityFramework or WebApi HttpClient, but with manual Tasks etc like below it does not work well, some are executed some are not. With Task.Run all are executed
_businessWorkerFactory().Run(async ctx =>
{
var guid = Guid.NewGuid();
System.Diagnostics.Debug.WriteLine("{0}: {1}", guid, Thread.CurrentThread.ManagedThreadId);
var completion = new TaskCompletionSource<bool>();
ThreadPool.QueueUserWorkItem(obj =>
{
Thread.Sleep(1000);
completion.SetResult(true);
});
await completion.Task;
System.Diagnostics.Debug.WriteLine("{0}: {1}", guid, Thread.CurrentThread.ManagedThreadId);
});
Task.Run schedules the task to run on a thread pool thread. The same thread pool that handles requests.
On an ASP.NET application, sending work to the thread pool steals threads that might be necessary to handle requests.
Given your requirements, I think you would be better queuing that work to another service/process using something like MSMQ.
Task.Run doesn't spawn a new thread - it borrows one from the thread pool (assuming the thread pool task scheduler - there's different schedulers, and you can write your own as well). When you use await inside of Task.Run, it will still work as usual - freeing the thread pool thread until a callback is posted.
However, exactly for that reason, there's little point in using Task.Run for I/O work. If you have asynchronous I/O to do, just do it - it will work exactly the same, without requiring a context switch. You must make it asynchronous though - if it's just blocking code, you're taking up valuable threads from the thread pool.
Note that you don't need for an asynchronous request to finish. If the asynchronous action you are performing doesn't need too much time to setup (that is, it returns the Task almost immediately, even though it isn't finished), you can just call it:
public async Task SomeAsync()
{
var request = new MyRequest();
await request.MakeRequestAsync();
...
}
public void Start()
{
var task = SomeAsync();
// Now the task is started, and we can use it for future reference. Or just wire up
// some error handling continuations etc. - though it's usually a better idea to do that
// within SomeAsync directly.
}