async/await with thread timer

白昼怎懂夜的黑 提交于 2019-12-13 08:56:23

问题


I was able resolve the issue with the input form Stephen Cleary. Please see update 3.

I have a Windows Forms application that has a method with the async modifier. If the method is called inside a button's click event it does not block the UI thread. However, when I call it inside a timer as a callback it freezes the UI. I could not figure out what I am doing wrong here. Please see below my code. This is just a sample project for demonstration purposes.

public Form1()
{
    InitializeComponent();            
}

private async void formCloseAsync()
{
    shutdown stf = new shutdown();
    stf.StartPosition = FormStartPosition.CenterScreen;
    stf.Show();
    var task = Task.Factory.StartNew(processClose);
    await task;
}

private void processClose()
{
    Thread.Sleep(5000);
    Environment.Exit(1);
}

private void simpleButtonAsync_Click(object sender, EventArgs e)
{
    formCloseAsync();
}        

private void _simpleButtonTimer_Click(object sender, EventArgs e)
{
    Timer _shutdownTimer = new Timer(delegate
    {
       formCloseAsync();
    }, null, 5000, Timeout.Infinite);
}

Update 1: Thanks All for your valuable input. Please see the updated code below

public Form1()
    {
        InitializeComponent();

    }

    private Timer _shutdownTimer;
    private void formCloseAsync()
    {
        shutdown stf = new shutdown();
        stf.StartPosition = FormStartPosition.CenterScreen;
        stf.Show();

        Task.Run(async ()=>
            { 
                await Task.Delay(5000);
                Environment.Exit(1);
            }
        );
    }

    private void simpleButtonAsync_Click(object sender, EventArgs e)
    {
        formCloseAsync();
    }

    private void _simpleButtonTimer_Click(object sender, EventArgs e)
    {
        _shutdownTimer = new Timer(async delegate
        {
            formCloseAsync();
        }, null, 0, Timeout.Infinite);
    }

However I still have the same issue. shutdown stf is blocked when called inside timer callback. Main UI is okay. No issue with that. I just want the shutdown(stf) GUI to be responsive when created from timer call back. Shutdown GUI has a progress bar.

Update 3:

Here is the final code

public partial class Form1 : Form
{
    readonly shutdown _stf = new shutdown();
    public Form1()
    {
        InitializeComponent();

    }

    private Timer _shutdownTimer;
    private async Task formCloseAsync()
    {

        try
        {
            BeginInvoke(new MethodInvoker(delegate
            {

                _stf.StartPosition = FormStartPosition.CenterScreen;
                _stf.Show();
            }));
            await Task.Run( async () =>
                            {
                                await Task.Delay(5000);
                            });

        }
        catch (Exception ex)
        {

            MessageBox.Show(ex.ToString());

        }
        finally
        {
            Environment.Exit(1);
        }

    }

    private  void simpleButtonAsync_Click(object sender, EventArgs e)
    {
        formCloseAsync();
    }

    private void _simpleButtonTimer_Click(object sender, EventArgs e)
    {
        _shutdownTimer = new Timer(async delegate
        {
            formCloseAsync();
        }, null, 0, Timeout.Infinite);
    }

    private async void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        e.Cancel = true;
         await formCloseAsync();
    }

回答1:


However, when I call it inside a timer as a callback it freezes the UI.

You can't access UI elements from background threads (I'm guessing stf.Show(); is showing a dialog). The easiest fix is probably to replace System.Threading.Timer with Windows.Forms.Timer.

Other notes:

  • You shouldn't use StartNew for that; use Task.Run instead. See my blog post StartNew is dangerous.
  • You shouldn't use async void for anything other than event handlers. See my MSDN article Best Practices in Asynchronous Programming.



回答2:


Use Task.Delay instead:

await Task.Delay(5000);

Since Thread.Sleep actually blocks the current thread and should not be used within an async method.

You can find out more about this here: When to use Task.Delay, when to use Thread.Sleep?



来源:https://stackoverflow.com/questions/39473228/async-await-with-thread-timer

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!