#c# #vb.net #multithreading
#c# #vb.net #многопоточность
Вопрос:
У меня есть a List(Of IWorker)
, который содержит несколько конкретных данных. IWorker
в свою очередь, имеет Startup()
Shutdown()
метод and .
Внутри рабочего класса Startup()
создается новый рабочий поток, затем возвращается. Shutdown()
в настоящее время устанавливает частный ShutDownRequested
флаг и возвращается. Флаг проверяется рабочим потоком (в худшем случае каждые несколько секунд).
Все это работает нормально, но в настоящее время родительское приложение не имеет возможности определить, завершил ли рабочий завершение работы.
Я вижу несколько способов обойти это, но не уверен, какой из них лучший.
- Добавьте
State
свойство вIWorker
. Должно сработать, но я собираюсь опрашивать состояния, которые кажутся немного неприятными. - Сделайте блокировку команды выключения — вероятно, это было бы моим идеальным решением, но я не уверен, как это реализовать — является ли рабочий
Sunclock
частным объектом, которыйShutdown()
также должен пытаться синхронизироваться после установки флага? - Что-то еще?
Любые статьи, советы или предложения приветствуются. Примеры на C # или VB подойдут.
Комментарии:
1. Это зависит от того, что вы хотите сделать и почему. Вы хотите блокировать при вызове
Shutdown()
? Вы хотите показать статус пользователю? Что-то еще?2. @svick Это выполняется в консольном приложении. В настоящее время после вызова запуска рабочих консоль просто выполняет цикл каждые несколько секунд, считывает некоторую информацию о состоянии от рабочих и отображает ее (обработанные события, используемая пропускная способность и т. Д.). Когда пользователь нажимает Enter для выхода из приложения, завершение работы отправляется каждому работнику. Я просто хочу дождаться завершения завершения работы, распечатать подтверждение чистого завершения работы и затем выйти. Если приложение не завершает работу и рабочий завершает работу, оно перерабатывается и запускается снова.
Ответ №1:
Я бы не стал пытаться использовать блокировку для блокировки Shutdown()
, если вы хотите, чтобы завершение работы было операцией блокировки.
Если вы можете использовать .NET 4, я бы сделал ваш внутренний метод выполнения задачей. Затем вы можете просто вызвать Task.Wait()
блокировку, пока она не будет завершена.
Если вы должны использовать .NET 3.5 или более раннюю версию, я бы Shutdown()
попросил внутренний вызов wait для WaitHandle, например a ManualResetEvent
. Код завершения работы может выглядеть следующим образом:
' Include:
Private shutdownEvent as ManualResetEvent = new ManualResetEvent(false)
Sub Shutdown()
ShutDownRequested = True
shutdownEvent.WaitOne()
End Sub
Затем цикл опроса (операция потока) будет выполнять:
Sub Execute()
While Not ShutDownRequested
' Do your work
End While
' Before you exit, "set" the event:
shutdownEvent.Set()
End Sub
Комментарии:
1. И используя задачи, вы также можете легко дождаться их всех сразу, используя
Task.WaitAll()
.2. Спасибо за подробный ответ. В настоящее время я застрял в 3.5 для этого проекта. Не могли бы вы объяснить, какие преимущества у вас
ManualResetEvent
есть по сравнению с использованиемThread.Join
, как предложено в другом ответе?3. @Basiclife Основными преимуществами являются: 1) Вы можете (необязательно) установить тайм-аут для WaitOne(), что позволит вам возвращаться, а не блокировать навсегда в случае плохо написанного
IWorker
, 2) вам не нужно сохранять ссылку на поток, что позволяет ему бытьGC’ed по завершении. 3) Очень четко указано, что происходит.4. @Reed спасибо за объяснение — все очень хорошие моменты, я буду использовать это в будущем.
Ответ №2:
Существует метод Thread .Соединение, которое будет блокироваться до тех пор, пока поток не закончится — какая-либо польза?
Ответ №3:
Почему бы не добавить ShutdownComplete
событие IWorker
и не убедиться, что это последнее, что делает каждый конкретный, когда он завершен? Я знаю, это звучит так, как будто это может заставить реализации делать что-то конкретное, но если у вас есть базовый класс для IWorker, это должно иметь большое значение. Подумайте об этом.
public abstract class WorkerBase : IWorker
{
public event EventHandler ShutdownComplete;
//...other implemenation details
public void Shutdown()
{
this.ShutdownInternal();
this.ShutdownComplete(this, EventArgs.Empty);
}
protected abstract void ShutdownInternal();
}