2009-02-27 5 views
3

Если у вас есть один основной поток, который запускает два других потока. Каков самый чистый способ заставить основной поток ждать двух других потоков?Подождите, пока закончите две нити

Я мог бы использовать bgndworker и sleep spinner, который проверяет IsBusy для рабочих bgnd, но я думаю, что есть лучший способ.

EDIT еще несколько требований:

  • Основной поток имеет некоторую другую работу, чтобы сделать (например, GUI).
  • Два порождали потоки должны быть в состоянии сообщить исключения и возвращать результат значения
+0

См. Также: http://stackoverflow.com/questions/540078/wait-for -pooled-threads-to-complete –

ответ

5

См. Ответы на this thread. Мне нравится this option ;-p

Forker p = new Forker(); 
p.Fork(delegate { DoSomeWork(); }); 
p.Fork(delegate { DoSomeOtherWork(); }); 
p.Join(); 

Re возвращение значение/исключение отчетности - просто каждая вилка сделать это в качестве обратного вызова в конце логики ... (вы можете использовать захваченные переменные для передачи состояния в обеих вилки, включая общий логгер и т. д.).

0

WaitHandle.WaitAny является вашим другом. Это позволяет вам ждать передачи нескольких потоков или других объектов.

http://msdn.microsoft.com/en-us/library/tdykks7z.aspx

EDIT:

На самом деле, WaitHandle.WaitAll является то, что вы хотите, не WaitAny.

http://msdn.microsoft.com/en-us/library/system.threading.waithandle.waitall.aspx

EDIT:

Соединить метод некоторые упоминания в порядке, но один недостаток заключается в том, что это не является полностью атомарной операцией. Это может или не важно для вас.

+0

В моей нынешней ситуации это не имеет значения, много, но я стараюсь получить основную идею из каждого вопроса, поэтому я могу применить его позже, когда возникают другие проблемы. Так что да, это важно в некотором роде. –

3
thread1.Join(); 
thread2.Join(); 
+0

Для этого требуется ванильная нить и не позволяет мне создавать исключения и т. Д. Не так ли? –

+3

Это был отличный ответ, прежде чем он добавил «Дополнительные требования». Он должен быть пользователем ... –

+0

Да - возможно, второй вопрос был бы уместным –

10

Краткое описание с использованием Thread.Join();

 Thread t1 = new Thread(new ThreadStart(delegate() 
     { 
      System.Threading.Thread.Sleep(2000); 
     })); 

     Thread t2 = new Thread(new ThreadStart(delegate() 
     { 
      System.Threading.Thread.Sleep(4000); 
     })); 

     t1.Start(); 
     t2.Start(); 

     t1.Join(); 
     t2.Join(); 

EDIT Другой 3example с помощью Wait Ручки:

  ManualResetEvent[] waitHandles = new ManualResetEvent[]{ 
      new ManualResetEvent(false), 
      new ManualResetEvent(false) 
     }; 

     Thread t1 = new Thread(new ParameterizedThreadStart(delegate(object state) 
     { 
      ManualResetEvent handle = (ManualResetEvent)state; 
      System.Threading.Thread.Sleep(2000); 
      handle.Set(); 
     })); 

     Thread t2 = new Thread(new ParameterizedThreadStart(delegate(object state) 
     { 
      ManualResetEvent handle = (ManualResetEvent)state; 
      System.Threading.Thread.Sleep(4000); 
      handle.Set(); 
     })); 

     t1.Start(waitHandles[0]); 
     t2.Start(waitHandles[1]); 

     WaitHandle.WaitAll(waitHandles); 

     Console.WriteLine("Finished"); 
+0

Второй экстаз мог бы помочь мне, я посмотрю на него –

+0

Есть ли способ использовать resetevents с фоном? –

+0

Подпишитесь на RunWorkerCompleted BackgroundWorker, который запускается, когда задача завершена, отменена или возникает исключение. –

1

В дополнение к другим ответам ... одна альтернатива "начать два потока и ждать, как закончить" является «начать один поток и сделайте одно задание самостоятельно, затем подождите, пока закончится другой поток ».

Конечно, если вы хотите начать два задания, выполните еще одну работу над основной нитью и , затем дождитесь окончания двух других потоков, что не так хорошо работает.

EDIT: Если основной поток представляет собой поток пользовательского интерфейса, вы не должны блокировать другие отделки резьбы - вы должны (IMO) заставить их вернуться к основному потоку, когда они закончили. Таким образом, вы все равно будете реагировать на пользовательский интерфейс во время выполнения.

+0

Да, действительная точка. Но, возможно, я упростил вопрос. Основной поток будет занят обновлением пользовательского интерфейса, поэтому не может быть обеспокоен тяжелыми задачами ввода-вывода. –

+0

Основной поток - это консольная нить. Он покажет некоторое повторное сообщение «Ожидание ...». Но я следую за вами на событиях вокруг прядения. См. Мой другой вопрос: http://stackoverflow.com/questions/594329/define-backgroundworkers-runworkercompleted-with-an-anonymous-method Или я полностью не в курсе? –

1

Вы не можете дождаться окончания и использовать GUI. Наилучшим подходом для этого является создание потоков и использование событий для взаимодействия с графическим интерфейсом. Помните, что в обработчике событий вы не можете изменять элемент управления. Вместо того, чтобы делать это напрямую, используйте метод Invoke.

+0

Обычно также требуется некоторая информация обратно в графический интерфейс, чтобы избежать использования событий для информации о ходе работы, если вы не хотите, чтобы поток был аутичным. Этот ответ - лучшее, что я мог прочитать на этой странице, спасибо! – jdehaan

Смежные вопросы