Я никогда раньше не использовал потоки в C #, где мне нужно иметь два потока, а также основной поток пользовательского интерфейса. В основном у меня есть следующее.
public void StartTheActions()
{
//Starting thread 1....
Thread t1 = new Thread(new ThreadStart(action1));
t1.Start();
// Now, I want for the main thread (which is calling `StartTheActions` method)
// to wait for `t1` to finish. I've created an event in `action1` for this.
// The I wish `t2` to start...
Thread t2 = new Thread(new ThreadStart(action2));
t2.Start();
}
Итак, по сути, мой вопрос заключается в том, как заставить поток ждать завершения другого. Каков наилучший способ сделать это?
c#
multithreading
Максим Заславский
источник
источник
Ответы:
Я вижу 5 доступных вариантов:
1. Thread.Join
Как с ответом Митча. Но это заблокирует ваш поток пользовательского интерфейса, однако вы получите встроенный тайм-аут.
2. Используйте
WaitHandle
ManualResetEvent
этоWaitHandle
как предложила Джриста.Стоит отметить, что если вы хотите дождаться нескольких потоков,
WaitHandle.WaitAll()
по умолчанию они не будут работать, так как для этого требуется поток MTA. Вы можете обойти это, пометив свойMain()
метод сMTAThread
- однако это блокирует вашу рассылку сообщений и не рекомендуется из того, что я прочитал.3. Запустить событие
Посмотрите эту страницу Джона Скита о событиях и многопоточности, возможно, что событие может стать неподписанным между ...
if
иEventName(this,EventArgs.Empty)
это случилось со мной раньше.(Надеюсь, эти компиляции я не пробовал)
4. Используйте делегата
Если вы используете метод _count, возможно, было бы (если быть безопасным) увеличить его, используя
Interlocked.Increment(ref _count)
Мне было бы интересно узнать разницу между использованием делегатов и событий для уведомления о потоках, единственное различие, которое я знаю, это то, что события вызываются синхронно.
5. Вместо этого делайте это асинхронно
Ответ на этот вопрос имеет очень четкое описание ваших вариантов с помощью этого метода.
Делегат / События в неправильной теме
Способ выполнения события / делегата будет означать, что ваш метод обработчика событий находится в thread1 / thread2, а не в основном потоке пользовательского интерфейса , поэтому вам нужно переключиться обратно вверху методов HandleThreadDone:
источник
Добавить
после того, как вы запустите его, но это не даст большого результата, поскольку это по сути тот же результат, что и запуск в основном потоке!
Я настоятельно рекомендую прочитать электронную книгу Джо Албахари по созданию потоков в C # , если вы хотите получить представление о потоках в .NET.
источник
Join
что буквально то, о чем спрашивает спрашивающий, в целом это может быть очень плохо. Вызов toJoin
повесит поток, из которого это делается. Если это основной поток GUI, это ПЛОХО ! Как пользователь я активно ненавижу приложения, которые, кажется, работают таким образом. Поэтому, пожалуйста, смотрите все остальные ответы на этот вопрос и stackoverflow.com/questions/1221374/…Предыдущие два ответа великолепны и будут работать для простых сценариев. Однако есть и другие способы синхронизации потоков. Следующее также будет работать:
ManualResetEvent является одним из различных WaitHandle , которые может предложить .NET Framework. Они могут обеспечить гораздо более широкие возможности синхронизации потоков, чем простые, но очень распространенные инструменты, такие как lock () / Monitor, Thread.Join и т. Д. Они также могут использоваться для синхронизации более двух потоков, что позволяет создавать сложные сценарии, такие как «главный» поток. который координирует несколько «дочерних» потоков, несколько параллельных процессов, которые зависят от нескольких этапов друг друга для синхронизации, и т. д.
источник
При использовании из .NET 4 этот пример может помочь вам:
от: https://stackoverflow.com/a/4190969/1676736
источник
Вам нужен
Thread.Join()
метод или одна из его перегрузок .источник
Я хотел бы, чтобы ваш основной поток передавал метод обратного вызова в ваш первый поток, и когда это будет сделано, он вызовет метод обратного вызова в основной цепочке, который может запустить второй поток. Это удерживает ваш основной поток от зависания во время ожидания соединения или ожидания. Передача методов в качестве делегатов в любом случае полезна для изучения на C #.
источник
Попробуй это:
источник
Публикуясь, чтобы помочь некоторым другим, потратил довольно много времени в поисках решения, подобного тому, что я придумал. Поэтому я выбрал немного другой подход. Выше есть счетчик, я применил его немного по-другому. Я раскручивал множество потоков, увеличивал счетчик и уменьшал счетчик, когда поток начинался и останавливался. Затем в основном методе я хотел приостановить и дождаться завершения потоков, что я и сделал.
Задокументировано в моем блоге. http://www.adamthings.com/post/2012/07/11/ensure-threads-have-finished-before-method-continues-in-c/
источник
Когда я хочу, чтобы пользовательский интерфейс мог обновлять свой дисплей в ожидании завершения задачи, я использую цикл while, который проверяет IsAlive в потоке:
источник
Вот простой пример, который ожидает завершения шага в том же классе. Он также выполняет вызов другого класса в том же пространстве имен. Я включил операторы using, чтобы он мог выполняться как Winform, пока вы создаете button1.
источник