Как вы закроете приложение, когда некоторые WATHANDLE в середине вызова в Waitone?
-
28-09-2019 - |
Вопрос
Есть ли стандартный способ закрыть приложение «чисто», а некоторые WaitHandle
Объекты могут быть в состоянии текущего блокирующего вызова к WaitOne
?
Например, может быть фоновая резьба, которая вращается вместе в способе, подобном этому:
while (_request.WaitOne())
{
try
{
_workItem.Invoke();
}
finally
{
OnWorkCompleted();
}
}
Я не вижу очевидного способа распоряжаться этой нитью, не вызывая Thread.Abort
(Что из того, что я понимаю, обескуражен). Призыв Close
на _request
объект (ан AutoResetEvent
Однако выбросит исключение.
В настоящее время нить, работающая на этой петле, имеет его IsBackground
Собственность набор true
, и поэтому приложение появляется точно закрыть. Однако, поскольку WaitHandle
внедрение IDisposable
, Я не уверен, считается ли это кошерным или если этот объект действительно должен быть расположен до выходов приложения.
Это плохой дизайн? Если нет, как этот сценарий обычно занимался?
Решение
Определите дополнительное WaitHandle
называется _terminate
это будет сигналить запрос, чтобы завершить петлю, а затем использовать WaitHandle.WaitAny
вместо WaitHandle.WaitOne
.
var handles = { _request, _terminate };
while (WaitHandle.WaitAny(handles) == 0)
{
try
{
_workItem.Invoke();
}
finally
{
OnCompleteWork();
}
}
Другие советы
Когда нить блокируется (независимо от того, на что он блокирует), вы можете позвонить Thread.Interrupt()
Это вызвало исключение ThreadInterruptedException
(Я полагаю, это может быть немного отличается) Вы можете справиться с этим исключением на самом потоке и выполнять какие-либо дополнительные уборки.
Стоит отметить, что нить будет бросать только ThreadInterruptedException
Когда он блокируется, если он не блокирует, его не будут брошены, пока он не будет брошен, пока он не пытается заблокировать.
Это «безопасный» способ окончания нитей от того, что я прочитал на эту тему.
Также стоит отметить: если объект реализует как idisposable, так и финизатор (который он будет, если он использует неуправляемые ресурсы), GC позвонит в финализатор, который обычно вызывает. Обычно это не определенное. Однако вы можете в значительной степени гарантировать, что они будут вызвать выпуск приложения. Только при особых обстоятельствах они не будут. (Определяющая среда .NET, такая как StackOverflowException
брошен)
Установить IsBackground
имущество true
... Он должен автоматически закрывать поток, когда ваше приложение заканчивается.
Поочередно, вы можете прервать нить, позвонив Thread.Interrupt
и обрабатывать ThreadInterruptedException
. Отказ Другая идея - позвонить _request.Set()
и сделать цикл Whance Проверьте летучий флаг, чтобы определить, закрывается ли приложение или должно ли продолжаться:
private volatile bool _running = true;
while(_request.WaitOne() && _running)
{
//...
}
// somewhere else in the app
_running = false;
_request.Set();
Я думаю, что операционная система будет очищена после завершения процесса. Поскольку ваш поток помечен как Isbackground, CLR завершит процесс и все потоки внутри, так что это не проблема.