How to do friendly cpu loop in c# - c#

I'm trying to check if boolean is true and if it's false keep checking until it's true. I find this and i don't really understand the example. I don't find anything and i try to do it easily but it isn't working it's freezing.
private void dashboard_Paint(object sender, PaintEventArgs e)
{
if (IsLogged().GetAwaiter().GetResult())
{
Console.WriteLine("Logged");
}
}
public async Task<Boolean> IsLogged()
{
while (!logged)
{
if (logged)
return true;
await Task.Delay(25);
}
return false;
}

Tasks in C# are a way to implement cooperative multitasking, where a number of tasks can potentially run on the same thread, each doing small amounts of work before yielding the cpu for other tasks to execute. If one of the tasks misbehaves and doesn't yield back to the task scheduler then the thread is blocked and no tasks will run until the block is cleared. When the task is invoked again it continues where it left off.
The default task scheduler runs tasks on a thread pool which helps to mitigate (but not eliminate) the impact of thread blocking. On WinForms though the task scheduler is set up to run tasks on the UI thread by default, since so many operations can only be done from the main thread. Overall this is a good thing, but it leads to problems whenever thread blocking comes up. Instead of blocking one of a group of thread pool threads, you're blocking the thread your UI and all of your other threads are running on.
The way to deal with this is to use async and await everywhere that it makes sense to do so. If you're ever waiting on a task to finish, use await to do it. If you ever find yourself using .Result, .Wait() or .GetAwaiter().GetResult() then ask yourself whether it can be rewritten as an async method, even if you have to use async void for event handlers.
For your paint event that means doing this:
private async void dashboard_Paint(object sender, PaintEventArgs e)
{
if (await IsLogged())
Console.WriteLine("Logged");
}
(While you shouldn't use async void in general, this is a requirement for async event handlers since the event signature is delegate void X(...) not delegate Task X(...).)
I won't get into why you should never have a wait in an OnPaint event handler, or why your IsLogged example has issues (and should probably be called WaitLogged instead), but there's one thing that you might want to be aware of just in case: the volatile keyword.
Assuming that logged is a field rather than a property, the optimizer can capture the value of the field and continue to use that captured value for the life of the method. The volatile keyword tells the optimizer that this shouldn't happen, and that every reference to logged should always result in a read from the variable rather than the captured value.
In the worst case you can end up with optimized code that looks something like this:
private async Task<bool> IsLogged()
{
if (!logged)
{
while (true)
await Task.Delay(25)
}
return true;
}
From the optimizer's point of view, that's what your code does. It doesn't know that the logged value can be changed by something else, so it doesn't consider that options. Adding volatile lets it know that it can't do that.

private async Task dashboard_Paint(object sender, PaintEventArgs e)
{
if (await IsLogged())
{
Console.WriteLine("Logged");
}
}
That should solve the issue with the freezing because GetAwaiter() sometimes freezes if not used correctly.
Have you tried checking to see what is setting the logging boolean to true? It seems like an infinite loop.

Related

Task.Wait for async method passes during application startup while it causes deadlock in WPF button handler

The behavior of Task.Wait() is unexpectedly different depending on the "environment" where invoked.
Calling Task.Wait() during application startup with below async method TestAsync passes (doesn't cause a deadlock) while the same code blocks when called from within a WPF Button handler.
Steps to reproduce:
In Visual Studio, using the wizard, create a vanilla WPF .NET framework application (e.g. named WpfApp).
In the App.xaml.cs file of the app file paste below Main method and TestAsync method.
In the project properties set Startup object to WpfApp.App.
In the properties of App.xaml switch Build Action from ApplicationDefinition to Page.
public partial class App : Application
{
[STAThread]
public static int Main(string[] args)
{
Task<DateTime> task = App.TestAsync();
task.Wait();
App app = new App();
app.InitializeComponent();
return app.Run();
}
internal static async Task<DateTime> TestAsync()
{
DateTime completed = await Task.Run<DateTime>(() => {
System.Threading.Thread.Sleep(3000);
return DateTime.Now;
});
System.Diagnostics.Debug.WriteLine(completed);
return completed;
}
}
Observe that the application starts properly (after 3sec delay) and that the "completed" DateTime is written to debug output.
Next create a Button in MainWindow.xaml with Click handler Button_Click in MainWindow.xaml.cs
public partial class MainWindow : Window
{
...
private void Button_Click(object sender, RoutedEventArgs e)
{
Task<DateTime> task = App.TestAsync();
task.Wait();
}
}
Observe that after clicking the Button, the application is deadlocked.
Why can't it pass in both cases?
Is there a way to change invocation (e.g. using ConfigureAwait at the correct task or somehow setting SynchronizationContext or whatever) so that it behaves identical in both invocations, but still synchronously waits for completion?
Update on limitations of the solution.
The async method like TestAsync comes from a library that cannot be changed.
The invocation code of the TestAsync method is nested within a callstack that cannot be changed either, and the code outside the callstck makes use of the returned value of the async method.
Ultimately the solution code has to convert the async method to run synchronous by not changing the method nor the caller.
This works well within UT code (NUnit) and during application startup, but no more within a handler of WPF.
Why?
There are a couple of different ways that you can handle this situation, but ultimately the reason there is a deadlock in one situation and not the other is that when called in the Main method SynchronizationContext.Current is null, so there isn't a main UI context to capture and all async callbacks are handled on thread pool threads. When called from the button, there is a synchronization context which is captured automatically, so all async callbacks in that situation are handled on the main UI thread which is causing the deadlock. In general the only way you won't get that deadlock is by forcing the async code to not capture the synchronization context, or use async all the way up and don't synchronously wait from the main UI context.
you can ConfigureAwait(false) inside of your TestAsync method so that it doesn't capture the synchronization context and try to continue on the main UI thread (this is ultimately what is causing your deadlock because you are calling task.Wait() on the UI thread which is blocking the UI thread, and you have System.Diagnostics.Debug.WriteLine(completed); that is trying to be scheduled back onto the UI thread because await automatically captures the synchronization context)
DateTime completed = await Task.Run<DateTime>(() => {
System.Threading.Thread.Sleep(3000);
return DateTime.Now;
}).ConfigureAwait(false);
You can start the async task on a background thread so that there isn't a synchronization context to capture.
private void Button_Click(object sender, RoutedEventArgs e)
{
var task = Task.Run(() => App.TestAsync());
var dateTime = task.Result;
}
you can use async up the whole stack
private async void Button_Click(object sender, RoutedEventArgs e)
{
Task<DateTime> task = App.TestAsync();
var dateTime = await task;
}
Given how you are using it, if you don't have to wait until the task is done, you can just let it go and it will finish eventually, but you lose the context to handle any exceptions
private void Button_Click(object sender, RoutedEventArgs e)
{
//assigning to a variable indicates to the compiler that you
//know the application will continue on without checking if
//the task is finished. If you aren't using the variable, you
//can use the throw away special character _
_ = App.TestAsync();
}
These options are not in any particular order, and actually, best practice would probably be #3. async void is allowed specifically for cases like this where you want to handle a callback event asynchronously.
From what I understand, in .NET many of the front ends have a single UI thread, and therefore must be written async all the way through. Other threads are reserved and utilized for things like rendering.
For WPF, this is why use of the Dispatcher and how you queue up work items is important, as this is your way to interact with the one thread you have at your disposal. More reading on it here
Ditch the .Result as this will block, rewrite the method as async, and call it from within the Dispatch.Invoke() and it should run as intended
Why can't it pass in both cases?
The difference is the presence of a SynchronizationContext. All threads start out without a SynchronizationContext. UI applications have a special UI thread(s) and at some point they need to create a SynchronizationContext and install it on that thread(s). Exactly when this happens isn't documented (or consistent), but it has to be installed at the point the UI main loop starts.
In this case, WPF will install it (at the latest) within the call to Application.Run. All user invocations from the UI framework (e.g., event handlers) happen within this context.
The blocking code deadlocks with the context because this is the classic deadlock situation, which requires three components:
A context that only allows one thread at a time.
An asynchronous method that captures that context.
A method also running in that context that blocks waiting for that asynchronous method.
Before the WPF code installed the context, condition (1) wasn't met, and that's why it didn't deadlock.
Is there a way to change invocation (e.g. using ConfigureAwait at the correct task or somehow setting SynchronizationContext or whatever) so that it behaves identical in both invocations, but still synchronously waits for completion?
We-ell...
This is a rephrasing of "how do I block on asynchronous code", and there's no good answer for that. The best answer is to not block on asynchronous code at all; i.e., use async all the way. Especially since this is GUI code, I'd say for the sake of UX you really want to avoid blocking. Since you're on WPF, you may find a technique like asynchronous MVVM data binding useful.
That said, there are a few hacks you can use if you must. Using ConfigureAwait is one possible solution, but not one I recommend; you'd have to apply it to all awaits within the transitive closure of all methods being blocked on (Blocking Hack). Or you can shunt the work to the thread pool (Task.Run) and block on that (Thread Pool Hack). Or you can remove the SynchronizationContext - unless the code being blocked on manipulates UI elements or bound data. Or there are even more dangerous hacks that I really can't recommend at all (Nested Message Loop Hack).
But even after putting in all the work for a hack, you'll still end up blocking the UI. The hacks are hard precisely because they're not recommended. It's quite a bit of work to give your users a worse experience. The far, far better solution (for your users and future code maintainers) is to go async all the way.

Questions about what runs on the main thread during c#'s async await

I'm having trouble understanding what runs on the main thread during an async await operation and would be grateful for some answers.
Let's say I have a button that is supposed to log the user in.
it is supposed to block all other user input while the login process transpires, show a progress view and then when the result comes in display it
and here is the method that performs the log in
button_clicked(object sender, EventArgs e) {
do_login(); //I do not await the result
do_some_other_stuff(); //this doesn't actually exist I just put it here to ask my questions
}
async Task do_login() {
string user_name = txtUser.Text;
string password = txtPassword.Text;
show_progress(true); //this is not an async method;
string error = await _login.do_login(user_name, password);//this is an async method that can take up to 20 seconds to complete;
show_progress(false);
if (error != null) {
show_error(error);
} else {
show_next_screen();
}
}
I have two questions on the above example
a) What will be run on the main thread?
If I understand it correctly only _login.do_login will be run on a seperate thread, all others will be on the main thread, is this correct?
b) In what order will the methods be executed?
Again if I understand it correctly, it will be :
do_login()
show_progress(true);
_login.do_login starts;
do_some_other_stuff();
_login.do_login finishes;
show_progress(false);
and it will continue from there
is this correct? if not, how can I achieve such a behaviour?
c) If my code above is correct then why do I keep receiving a warning that do_login() is not awaited? I do not wish to await it I just want it to run what it can and return when it wants, should I ignore that warning?
Technically, depending on the implementation of do_login, everything could run in the main thread. In this case I assume you're contacting a web server, so that part won't, but this is not always true. And asynchronous operation does not necessarily executes in another thread. One operation is asynchronous when:
It doesn't block the calling thread.
Usually, UI threads run an 'event loop'. So an asynchronous task could simply put a new piece of work into the event queue to be executed whenever the scheduler determines, but in the same thread. In this case you don't use two threads, but still, you don't have to wait for the task to complete and you don't know when it'll finish.
To be precise, all the code in your post will run in the main thread. Only the part in do_login that manages the connection with the server, waiting and retrieving data will execute asynchronously.
You're mostly right about the sequence, with a few adjustments:
do_login() (until the await)
login._do_login() starts executing
do_some_other_stuff()
...
login.do_login finishes
show_progress()
The answer to your main question is: it depends. The _login.do_login method will likely be put onto its own thread, but it actually depends on the .NET task scheduler. In WPF and ASP.NET it will be scheduled onto the thread pool if it doesn't immediately return a completed task.
The important part is that you know it will not block execution of the calling (in your case, the main) thread. Your understanding of the method flow is correct since you don't await do_login.
As far as the warning goes; you can mark do_login as async void to avoid it, though generally you only do that for event handlers which can then await a Task returning method. If you do go the async void route; make sure to put a try/catch in as such methods will throw all the way up to the root handler and can cause your app to crash.

C# await tasks + infinite loop still freezing the UI

I am trying to get the proper 'structure' for monitoring the state of a game from external source(s) using (Tasks) async/await in order to run the tasks in an infinite loop, however the current way its written seems to just freeze up my UI.
What I have so far:
(in the "state machine" class)
// Start monitoring the game state for changes
public void Start()
{
tokenSource = new CancellationTokenSource();
CancellationToken token = tokenSource.Token;
IsRunning = true;
task = Task.Factory.StartNew(async () =>
{
while (true)
{
await Task.Run(()=>CheckForStateChange());
await Task.Delay(1000); // Pause 1 second before checking state again
}
}, token, TaskCreationOptions.LongRunning, TaskScheduler.FromCurrentSynchronizationContext());
}
Without the above "Task.Delay" line the UI completely freezes up. With the "Task.Delay" line it doesn't freeze up, but if I try to drag the window it skips back to where I began dragging it.
My assumption with the current code is that the 'await Task.Run()' executes and upon completion the 'await Task.Delay()' executes and then on completion returns to the beginning of the while(true) infinite loop. (ie. not running in parallel).
The CheckForStateChange() signature is as follows:
private void CheckForStateChange()
{
// ... A bunch of code to determine and update the current state value of the object
}
Nothing special there, simple non-async method. I have read through lots of examples / questions here on StackOverflow and I used to have CheckForStateChange as returning a Task (with awaitable actions inside the method) and many other iterations of code (with the same results).
Finally I call the Start() method from the main win32 form (button) as follows:
private void btnStartSW_Click(object sender, EventArgs e)
{
// Start the subscription of the event handler
if(!state.IsRunning)
{
state.StateChange += new SummonersWar.StateChangeHandler(OnGameStateChange);
state.Start();
}
}
I think the above code is the simplest form I have written the code structure in so far, but apparently its still not written 'properly'. Any help would be appreciated.
UPDATE:
The publisher side (state machine class):
// ------ Publisher of the event ---
public delegate void StateChangeHandler(string stateText);
public event StateChangeHandler StateChange;
protected void OnStateChange() // TODO pass text?
{
if (StateChange != null)
StateChange(StateText());
}
Where the StateText() method is just a temporary way of retrieving a 'text' representation of the current state (and is really a placeholder at this point until I organize it into a tidier struct)
IsRunning is purely a public bool.
And the handler in the UI thread:
private void OnGameStateChange(string stateText)
{
// Game State Changed (update the status bar)
labelGameState.Text = "State: " + stateText;
}
Why the UI freezes
In terms of the main question: you're already calling your CheckForStateChange via Task.Run, so there is no way that your CheckForStateChange will freeze the UI unless it includes calls which are marshalled back to the UI thread (i.e. Control.Invoke or SynchronizationContext.Post/Send used explicitly, or implicitly via a Task started on the UI TaskScheduler).
The best place to start looking is your StateChange handlers (i.e. StateChangeHandler). Also have a look at where the StateChange event is raised. You'll find thread marshalling code at one of these sites.
Other issues
You're passing the TaskScheduler pointing to the UI SynchronizationContext to the outer task. You're also passing in TaskCreationOptions.LongRunning. In simple terms you're telling the task factory to "start a task on a dedicated thread, and on the current thread". These two are mutually exclusive requirements and you can pretty safely drop them both.
If, as a result of the above, your outer task happens to execute on the UI thread, it won't really trip you up as the inner call is wrapped in Task.Run, but this probably isn't the behaviour you expect.
You are storing the result of Task.Factory.StartNew inside a task field or property. Note, however, that your Task.Factory.StartNew call returns a Task<Task>, so the saved Task instance will transition to completed state almost immediately unless you call Unwrap on it and get to the inner task. To avoid this entire mess, just use Task.Run to create the outer task (as it has Unwrap semantics built in). If you do that, you can ditch the inner Task.Run completely, like so:
public bool IsRunning
{
get
{
return task.Status == TaskStatus.Running;
}
}
public void Start()
{
tokenSource = new CancellationTokenSource();
CancellationToken token = tokenSource.Token;
task = Task.Run(async () =>
{
while (true)
{
CheckForStateChange(token);
token.ThrowIfCancellationRequested();
await Task.Delay(1000); // Pause 1 second before checking state again
}
}, token);
// Uncomment this and step through `CheckForStateChange`.
// When the execution hangs, you'll know what's causing the
// postbacks to the UI thread and *may* be able to take it out.
// task.Wait();
}
Since you have a CancellationToken you need to be passing it to CheckForStateChange, and checking it periodically - otherwise it only gets checked once, when the Task is started, and then never again.
Note that I have also provided a different IsRunning implementation. Volatile state is hard to get right. If the framework is giving it to you for free, you should use it.
Final word
Overall this entire solution feels like a bit of a crutch for something that should be done more reactively - but I can think of scenarios where this sort of design is valid. I'm just not convinced that yours is really one of them.
EDIT: how to find what's blocking the UI
I'll get downvoted to oblivion for this, but here goes:
The sure way to find what's causing postbacks to the UI thread is to deadlock with it. There's plenty of threads here on SO telling you how to avoid that, but in your case - we'll cause it on purpose and you'll know exactly what calls you need to avoid when you're polling for changes - although whether or not it will be possible to avoid these calls, remains to be seen.
I've put a task.Wait instruction at the end of my code snippet. Provided that you call Start on the UI thread, that should cause a deadlock with something inside your CheckForStateChange, and you will know what it is that you need to work around.

Why does async method-callers behave strangely?

I'm working on a Windows 8.1 store app in which the user can save text to a file.
I've been trying to understand how to best use async and await.
This is what I've come up with:
private async void userText_KeyDown(object sender, KeyRoutedEventArgs e)
{
if (e.Key == Windows.System.VirtualKey.Enter)
{
if (addUserImput)
{
userStringlist.Add(userBox.Text);
userBox.Text = "";
addUserImput = false;
}
await WriteToFileAsync();
addUserImput = true;
}
}
And the async-method looks like this:
private async Task WriteToFileAsync()
{
string name = "userStrings.txt";
var option = CreationCollisionOption.ReplaceExisting;
var folder = Windows.Storage.ApplicationData.Current.LocalFolder;
var file = await folder.CreateFileAsync(name, option);
await Windows.Storage.FileIO.WriteLinesAsync(file, userStringlist);
}
As soon as WriteToFileAsync reaches the await-keyword the execution will start over. In order to prevent duplicates in my list I had to add the if-statement.
It just strikes me as odd. I'm still new to this, so I might've missed something. Why does the keydown event resume from the top, doing work that has already been done?
My "workaround" works, I just don't get the logic behind the event's behaviour.
Yes, that's how asynchronous solutions work. When you hit your first actually asynchronous operation (in this case, CreateFileAsync) the method returns to its caller, which returns to its caller, and it eventually works it's way out of the entire method and back up to your application's message loop. It then continues on processing other UI messages. Some of those messages may be key down events (and they could end up being run before your asynchronous operation is completed). Other events could be things like paint events or mouse click events that lets your form do whatever it needs to interact with the user. This is what prevents it from freezing.
What you want to do is to prevent the given section of code that you have from being run concurrently. If this weren't asynchronous this is something that you would generally solve using the lock keyword, but that isn't an option for an asynchronous method. What you need is some method of preventing access to the code until any other executions of that code block finish. Fortunately there are tools available to do this. You could use a boolean, as you are, but this is somewhat fragile and fairly easy to make a mistake with as the complexity of the application grows. A Semaphore is specifically designed for this task:
private SemaphoreSlim semaphore = new SemaphoreSlim(1);
private async void Bar()
{
try
{
await semaphore.WaitAsync();
//do stuff
}
finally
{
semaphore.Release();
}
}
The SemaphoreSlim class has a WaitAsync method specifically designed for use in asynchronous methods, such as yours. You can wait until the semaphore is free, do your code, and then ensure that you release the semaphore when done so that other code can then move into the code block.
You may need to use handled = true in this case . check if http://msdn.microsoft.com/en-us/library/system.windows.forms.keyeventargs.handled(v=vs.110).aspx works

Working with TPL Using Embedded Tasks

I am running a process on a separate thread to facilitate concurrency and a smooth user interface calling
private void ThreadedTestConnection(SqlConnection conn, bool bShowErrMsg)
{
Task<bool> asyncTestConn = Task.Factory.StartNew<bool>
(() => TestConnection(conn, bShowErrMsg));
return asyncTestConn.Result;
asyncTestConn.Dispose();
}
from the UI thread. However, the 'wait' caused by return asyncTestConn is stopping the UI thread being release back to the GUI. I have come up with the following fix. From an event fired from the GUI I have (not including try/catch blocks)
private void SomeClick_Event(object sender, EventArgs e)
{
Task testConnection = Task.Factory.StartNew
(() => UtilsDB.ThreadedTestConnection(mainConn, true));
}
This works. That is, it returns control to the GUI immediately whilst running the test on a seperate background thread. Am I being a very foolish boy in doing this, or is this Okay?
Note: This is a seperate question but related to this one I have not recived a satasfactory answer for.
This is perfectly fine, you are just starting a "fire and forget" task which will run on a thread-pool thread - however in the first example you seem to expect a result (I assume a boolean indicating whether the connection test was successful) - in the second you won't have any - unless your task e.g. raises an event or calls a predefined callback.

Categories