-3

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;
}
aepot
  • 4,558
  • 2
  • 12
  • 24
  • You haven’t tagged your question with what UI framework you’re using, but I’m guessing Windows Forms from the method signature. So make `dashboard_PaintAsync ` async, and get rid of `.GetAwaiter().GetResult()` – stuartd Jun 12 '22 at 23:39
  • ?? My question tag is "c#" –  Jun 12 '22 at 23:40
  • Sorry, pressed Enter by accident before – stuartd Jun 12 '22 at 23:41
  • Uhm i was using async task in my event that's why i have ..._PaintAsync (just a little error of mine) but i remove it because it's was doing non-sence errors –  Jun 12 '22 at 23:44
  • 1
    `GetAwaiter().GetResult()` is _synchronous_ - which is why your UI freezes. See [this question](https://stackoverflow.com/questions/17284517/is-task-result-the-same-as-getawaiter-getresult), especially the first comment on the question. – stuartd Jun 12 '22 at 23:46
  • This way is algorithmically called polling. Polling almost always a bad practice because almost always exists a better way to solve the problem without polling. – aepot Jun 12 '22 at 23:52
  • `if (IsLogged().Result)` still freezing my UI. –  Jun 12 '22 at 23:54
  • aepot Like what? –  Jun 12 '22 at 23:55
  • Answer deleted because I completely lost contact with the problem and can't catch the idea what's really happening. Then try to edit the question and place the whole details required for problem understanding. I know one thing: you mustn't wait in paint-related event handler, it's not intended for waiting inside. If you want conditionally to skip the drawing then just return from the method before the drawing anything. Painting event handler must be executed as fast as possible otherwise it will slow down the app's performance or freeze it. – aepot Jun 13 '22 at 01:25

2 Answers2

1

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.

Corey
  • 15,524
  • 2
  • 35
  • 68
0
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.

  • It would solve the issue because GetAwaiter() is a method while .Result is a property and won't execute a function. .Result is a guarantee that you would not encounter any freezes. – Jeff Freedman Jun 12 '22 at 23:56
  • Jeff Freedman I still get my UI freezed –  Jun 13 '22 at 00:00
  • Try this then - private async Task dashboard_Paint(object sender, PaintEventArgs e) { if (await IsLogged()) { Console.WriteLine("Logged"); } } – Jeff Freedman Jun 13 '22 at 00:04
  • I have edited the method above. – Jeff Freedman Jun 13 '22 at 00:05
  • As i tell in previous comment i have non-sence error if you have fix tell me: **Error CS0407 'Task dashboard.dashboard_Paint(object, PaintEventArgs)' does not have correct return type** –  Jun 13 '22 at 00:07
  • The method above is an equivalent to a void. Are you trying to receive a return value from the method above? – Jeff Freedman Jun 13 '22 at 00:10
  • No i don't return anything on it –  Jun 13 '22 at 00:13
  • 1
    Did you try the example that I have provided? I have tested it on my own compiler and it worked. – Jeff Freedman Jun 13 '22 at 00:16
  • Yes i try it, there no return in my paint event and still not work –  Jun 13 '22 at 00:20
  • @JeffFreedman `.Result` blocks until the task completes. If the task hasn't completed then it basically calls `.Wait()` before returning the result value. Properties getters and setters are methods, never assume they're just a simple read/write of the underlying field. – Corey Jun 13 '22 at 00:28