问题
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 usecontrol.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