开发者

How can I wait for a thread to finish running other than by calling thread.Join()?

I am working on a project where the methods are called from the an application which is available with the library.

I have the below code in my button click event:

Thread thread = new Thread(new ThreadStart(AddPics));
thread.Priority = ThreadPriority.Highest;
thread.Start();
execute();

But while running the sample always the execution point moves to the execute. How to make the program to execute the AddPics method first. I have tried thread.Join() and it worked, but I want to kno开发者_高级运维w if there is any other way to achieve this.


You can use Join or AutoResetEvent to wait until add picture thread finishes, But you should not use either as explained later on the answer.

You can achieve the same results by using AutoResetEvent as alternative to Join; it allows you to setup a blocking-notification, so block before calling the execute() method and only proceed when AddPics thread finishes its job:

private AutoResetEvent _finishAddPicsNotifier = new AutoResetEvent(false);

private void OnMyButton_Click(object sender, EventArgs e)
{
    //.....
    new Thread(AddPics)
    {
        Priority = ThreadPriority.Highest,
        IsBackground = true, //will explain later
    }.Start();

    _finishAddPicsNotifier.WaitOne();//this will block until receive a signal to proceed
    execute();//this method will only be called after the AddPics method finished
    /.....
}

private void AddPics()
{
    try{
        //.......
    }
    finally{
        _finishAddPicsNotifier.Set();//when finished adding the pictures, allow the waiting method to proceed
    }
}

Note: Set IsBackground = true to indicates that thread is a background thread so it will not prevent the application from terminating. read more about background thread here.

Problems:

  • Since you are using a button click to run the thread, you should add some mechanism to prevent multi-clicks at the same time to run the code multiple time.
  • You are also blocking the UI thread when call Join() or _finishAddPicsNotifier.WaitOne().

To fix all of that, a good design is to define a method OnFinishAddingPictures and call it whenever finish adding images, inside this new method call execute(), you should also remove the previous execute() call from button click:

private readonly object _oneAddPicturesLocker = new object();

private void OnMyButton_Click(object sender, EventArgs e)
{
    //.....
    new Thread(AddPics)
    {
        Priority = ThreadPriority.Highest,
        IsBackground = true,
    }.Start();
}

private void AddPics()
{
    if (Monitor.TryEnter(_oneAddPicturesLocker))
    {
        //we only can proceed if no other AddPics are running.
        try
        {
            //.....

            OnFinishAddingPictures();
        }
        finally
        {
            Monitor.Exit(_oneAddPicturesLocker);
        }
    }
}

private void OnFinishAddingPictures()
{
    execute();
}

Note:

  • We get rid of the blocking using this mechanism.
  • We are sure One and Only one call to the AddPics are executed at a moment.
  • Always remember to check InvokeRequired and use control.Invoke(/*..*/) whenever accessing form or control methods and properties from a thread that is not the UI thread.


I assuming that your primary point is to have responsive UI while the thread with AddPics is running? If so, then you can use this construction for WinForms:

while (thread.IsAlive)
    System.Windows.Forms.Application.DoEvents();
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜