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

泪湿孤枕 提交于 2020-01-03 20:48:48

问题


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 know if there is any other way to achieve this.


回答1:


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.



回答2:


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();


来源:https://stackoverflow.com/questions/6423380/how-can-i-wait-for-a-thread-to-finish-running-other-than-by-calling-thread-join

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