Я вижу 5 доступных вариантов:
1. Thread.Join
Как с ответом Митча. Но это заблокирует ваш поток пользовательского интерфейса, однако вы получите встроенный тайм-аут.
2. Используйте WaitHandle
ManualResetEvent
это WaitHandle
как предложила Джриста.
Стоит отметить, что если вы хотите дождаться нескольких потоков, WaitHandle.WaitAll()
по умолчанию они не будут работать, так как для этого требуется поток MTA. Вы можете обойти это, пометив свой Main()
метод сMTAThread
- однако это блокирует вашу рассылку сообщений и не рекомендуется из того, что я прочитал.
3. Запустить событие
Посмотрите эту страницу Джона Скита о событиях и многопоточности, возможно, что событие может стать неподписанным между ... if
и EventName(this,EventArgs.Empty)
это случилось со мной раньше.
(Надеюсь, эти компиляции я не пробовал)
public class Form1 : Form
{
int _count;
void ButtonClick(object sender, EventArgs e)
{
ThreadWorker worker = new ThreadWorker();
worker.ThreadDone += HandleThreadDone;
Thread thread1 = new Thread(worker.Run);
thread1.Start();
_count = 1;
}
void HandleThreadDone(object sender, EventArgs e)
{
// You should get the idea this is just an example
if (_count == 1)
{
ThreadWorker worker = new ThreadWorker();
worker.ThreadDone += HandleThreadDone;
Thread thread2 = new Thread(worker.Run);
thread2.Start();
_count++;
}
}
class ThreadWorker
{
public event EventHandler ThreadDone;
public void Run()
{
// Do a task
if (ThreadDone != null)
ThreadDone(this, EventArgs.Empty);
}
}
}
4. Используйте делегата
public class Form1 : Form
{
int _count;
void ButtonClick(object sender, EventArgs e)
{
ThreadWorker worker = new ThreadWorker();
Thread thread1 = new Thread(worker.Run);
thread1.Start(HandleThreadDone);
_count = 1;
}
void HandleThreadDone()
{
// As before - just a simple example
if (_count == 1)
{
ThreadWorker worker = new ThreadWorker();
Thread thread2 = new Thread(worker.Run);
thread2.Start(HandleThreadDone);
_count++;
}
}
class ThreadWorker
{
// Switch to your favourite Action<T> or Func<T>
public void Run(object state)
{
// Do a task
Action completeAction = (Action)state;
completeAction.Invoke();
}
}
}
Если вы используете метод _count, возможно, было бы (если быть безопасным) увеличить его, используя
Interlocked.Increment(ref _count)
Мне было бы интересно узнать разницу между использованием делегатов и событий для уведомления о потоках, единственное различие, которое я знаю, это то, что события вызываются синхронно.
5. Вместо этого делайте это асинхронно
Ответ на этот вопрос имеет очень четкое описание ваших вариантов с помощью этого метода.
Делегат / События в неправильной теме
Способ выполнения события / делегата будет означать, что ваш метод обработчика событий находится в thread1 / thread2, а не в основном потоке пользовательского интерфейса , поэтому вам нужно переключиться обратно вверху методов HandleThreadDone:
// Delegate example
if (InvokeRequired)
{
Invoke(new Action(HandleThreadDone));
return;
}