Home > other >  How to do friendly cpu loop in c#
How to do friendly cpu loop in c#

Time:06-13

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;
}

CodePudding user response:

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.

CodePudding user response:

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.

  • Related