0

I want to asynchronously update UI status when doing a long-time task . The program is a console application , however , when I execute the async operations , the UI thread will exit soon after the task begins . How should I let the UI thread wait when my long-time task finish ?

I simplify my code as below :

public static class Program
{
    static void Main()
    {
        WorkerWrapper wp = new WorkerWrapper();
        wp.ProcessData();
    }
}

public class WorkerWrapper
{
    private RateBar bar;

    public void ProcessData()
    {
        bar = new RateBar();
        bar.Show();

        Worker wk = new Worker();
        wk.WorkProcess += wk_WorkProcess;

        Action handler = new Action(wk.DoWork);
        var result = handler.BeginInvoke(new AsyncCallback(this.AsyncCallback), handler);
    }

    private void AsyncCallback(IAsyncResult ar)
    {
        Action handler = ar.AsyncState as Action;
        handler.EndInvoke(ar);
    }

    private void wk_WorkProcess(object sender, PrecentArgs e)
    {
        if (e.Precent < 100)
        {
            bar.Precent = e.Precent;
        }
    }
}

public class Worker
{
    public event EventHandler<PrecentArgs> WorkProcess;
    public void DoWork()
    {
        for (int i = 0; i < 100; i++)
        {
            WorkProcess(this, new PrecentArgs(i));
            Thread.Sleep(100);
        }
    }
}

public class PrecentArgs : EventArgs
{
    public int Precent { get; set; }
    public PrecentArgs(int precent)
    {
        Precent = precent;
    }
}

public partial class RateBar : Form
{
    public int Precent
    {
        set
        {
            System.Windows.Forms.MethodInvoker invoker = () => this.progressBar1.Value = value;
            if (this.progressBar1.InvokeRequired)
            {
                this.progressBar1.Invoke(invoker);
            }
            else
            {
                invoker();
            }
        }
    }

    public RateBar()
    {
        InitializeComponent();
    }
}

However , in method ProcessData() , if I add result.AsyncWaitHandle.WaitOne() in the end to wait my operation to complete , the Form will freeze .

Is there anything wrong with my way to wait the thread to complete ?

wlz
  • 563
  • 1
  • 4
  • 9

3 Answers3

0

Reason that your application exiting before your "background threads" completed is when there are multiple threads application exists soon after there are not any foreground threads. This is explained more in here http://msdn.microsoft.com/en-us/library/system.threading.thread.isbackground(v=vs.110).aspx

You should add proper waiting mechanisms to your background threads to be completed. There are multiple ways of letting other threads know that the thread is complete. Please refer here. How to wait for thread to finish with .NET?

Community
  • 1
  • 1
DSharper
  • 3,177
  • 9
  • 29
  • 47
  • If I use `result.AsyncWaitHandle.WaitOne()` to wait the thread to complete , the Form will freeze . Is there anything wrong ? @DSharper – wlz May 27 '14 at 07:11
  • have you tried making "DoWork" method to run as foreground thread by setting isBackground = false? @wlz – DSharper May 27 '14 at 08:29
0

You shouldn't block the UI thread waiting for the result, but rather retrieve the result from EndInvoke. Your deadlock probably occurs because you are using both result.AsyncWaitHandle.WaitOne() and EndInvoke, both will block until the result is available.

In my opinion the best option is to not call result.AsyncWaitHandle.WaitOne() and just retrieve the result in the AsyncCallback

private void AsyncCallback(IAsyncResult ar)
{
    Action handler = ar.AsyncState as Action;
    var result = handler.EndInvoke(ar);               
}

More information here. Also if you are using .net 4.0 or higher, this sort of thing can be done much easier with async/await.

NeddySpaghetti
  • 13,187
  • 5
  • 32
  • 61
0

I write down this solution and hope it may helps others with same question . The key to this problem is to use a new thread to run RateBar's ShowDialog function .

 public void ProcessData()
 {
     new Thread(() => new RateBar().ShowDialog()).Start(); 

     Worker wk = new Worker();
     wk.WorkProcess += wk_WorkProcess;

     Action handler = new Action(wk.DoWork);
     var result = handler.BeginInvoke(new AsyncCallback(this.AsyncCallback), handler);
 }
wlz
  • 563
  • 1
  • 4
  • 9