Я читал на Поточной обработке.NET, и работал над некоторым кодом, который использует ManualResetEvent. Я нашел много примеров кода в Интернете. Однако при чтении документации для WaitHandle, я видел следующее:
WaitHandle реализует Расположить шаблон. Посмотрите, что Реализация Завершает и Располагает для Чистки Неуправляемых ресурсов.
Ни один из образцов, кажется, не называет.Close () на объектах ManualResetEvent, которые они создают, даже хорошая статья Recursion и Concurrency из блога pfxteam (Редактирование - это имеет блок использования, который я пропустил). Этот справедливый контроль в качестве примера, или не нужен? Мне любопытно, потому что WaitHandle "инкапсулирует операционные системные конкретные объекты", таким образом, могла легко быть утечка ресурсов.
В общем, если объект реализует IDisposable
, он делает это по определенной причине, и вам следует вызвать Dispose
(или Close
, в зависимости от обстоятельств). ). В примере, который вы размещаете, ManualResetEvent заключен в оператор using
, который «автоматически» обрабатывает вызовы Dispose
. В этом случае Close
является синонимом Dispose
(что верно в большинстве IDisposable
реализаций, которые предоставляют метод Close
).
Код из примера:
using (var mre = new ManualResetEvent(false))
{
...
}
расширяется до
var mre = new ManualResetEvent(false);
try
{
...
}
finally
{
((IDispoable)mre).Dispose();
}
Close обрабатывается внутри ManualResetEvent Dispose и вызывается оператором using.
http://msdn.microsoft.com/en-us/library/yh598w02%28VS.100%29.aspx
Я часто использую ManualResetEvent
и не думаю, что когда-либо использовал его внутри отдельного метода - это всегда поле экземпляра класса. Поэтому using()
часто не применяется.
Если у вас есть поле экземпляра класса, которое является экземпляром ManualResetEvent
, сделайте свой класс реализующим IDisposable
и в своем методе Dispose()
вызовите ManualResetEvent.Close()
. Затем во всех случаях использования вашего класса вам нужно использовать using()
или заставить содержащий класс реализовать IDisposable
и повторять, и повторять...
Если вы используете ManualResetEvent
с анонимными методами, тогда это очевидно полезно. Но, как упоминал Сэм, их часто можно передать рабочим, а затем установить и закрыть.
Я бы сказал, что это зависит от контекста того, как вы его используете - образец кода MSDN WaitHandle.WaitAll () дает хороший пример того, что я имею в виду.
Вот пример, основанный на образце MSDN, как создание WaitHandles с помощью оператора using
будет исключением:
System.ObjectDisposedException
«Безопасный дескриптор был закрыт»
const int threads = 25;
void ManualWaitHandle()
{
ManualResetEvent[] manualEvents = new ManualResetEvent[threads];
for (int i = 0; i < threads; i++)
{
using (ManualResetEvent manualResetEvent = new ManualResetEvent(false))
{
ThreadPool.QueueUserWorkItem(new WaitCallback(ManualWaitHandleThread), new FileState("filename", manualResetEvent));
manualEvents[i] = manualResetEvent;
}
}
WaitHandle.WaitAll(manualEvents);
}
void ManualWaitHandleThread(object state)
{
FileState filestate = (FileState) state;
Thread.Sleep(100);
filestate.ManualEvent.Set();
}
class FileState
{
public string Filename { get;set; }
public ManualResetEvent ManualEvent { get; set; }
public FileState(string fileName, ManualResetEvent manualEvent)
{
Filename = fileName;
ManualEvent = manualEvent;
}
}
Вы заметите, что в коде
using (var mre = new ManualResetEvent(false))
{
// Process the left child asynchronously
ThreadPool.QueueUserWorkItem(delegate
{
Process(tree.Left, action);
mre.Set();
});
// Process current node and right child synchronously
action(tree.Data);
Process(tree.Right, action);
// Wait for the left child
mre.WaitOne();
}
используется ключевое слово 'using'. Это автоматически вызывает метод dispose по завершении работы, даже если код выбрасывает исключение.
Мне недавно отправили отрывок из C # 4.0 в двух словах: окончательная ссылка Джозеф Альбахари, Бен Альбахари. На странице 834 в Глава 21: Threading есть раздел, в котором говорится об этом.
Удаление дескрипторов ожидания
Закончив с дескриптором ожидания , вы можете вызвать его метод Close , чтобы освободить операционную систему {{1} } ресурс. В качестве альтернативы вы можете просто отбросить все ссылки на дескриптор ожидания и позволить сборщику мусора выполнить эту работу за вас когда-нибудь позже (дескрипторы ожидания реализуют шаблон удаления , при котором финализатор вызывает Close ). Это один из немногих сценариев, в которых использование этой резервной копии является (возможно) приемлемым, поскольку дескрипторы ожидания несут легкую нагрузку на ОС (асинхронные делегаты полагаются на именно этот механизм для освобождения дескриптора ожидания их IAsyncResult ).
Дескрипторы ожидания освобождаются автоматически, когда приложение выгружает домен.