Проблема:
Я использую асинхронную обработку событий в классе, который вызывает событие примерно 60 раз в секунду.Если я запускаю программное обеспечение в течение нескольких часов, я обнаруживаю, что оно в конечном итоге переходит в состояние, когда событие перестает вызывать назначенного делегата, не видя никаких исключений или ввода данных пользователем.
Вот измененная версия кода события, которым я являюсьиспользуя:
class DataSource
{
public event EventHandler<DataReadyEventArgs> DataReady;
private void OnDataReady()
{
EventHandler<DataReadyEventArgs> evt = DataReady;
if (evt != null)
{
Trace.WriteLine("Invoking DataReady...");
DataReadyEventArgs args = new DataReadyEventArgs();
evt.BeginInvoke(this, args, new AsyncCallback(DataReadyHandled), null);
}
}
private void DataReadyHandled(IAsyncResult result)
{
AsyncResult aresult = result as AsyncResult;
EventHandler<DataReadyEventArgs> evt = aresult.AsyncDelegate as EventHandler<DataReadyEventArgs>;
if (evt != null)
{
try
{
evt.EndInvoke(result);
Trace.WriteLine("DataReady was handled.");
}
catch
{ }
}
}
}
class DataConsumer
{
public DataConsumer(DataSource src)
{
src.DataReady += HandleDataReady;
}
public void HandleDataReady(object sender, DataReadyEventArgs e)
{
Trace.WriteLine("Handling DataReady");
}
}
Чтобы не записывать дополнительный код для получения полной картины, вы также можете сделать следующие предположения:
- Всегда существует сильная ссылка на
DataSource
экземпляр, поэтому он не подвергается сборке мусора, пока DataConsumer
ожидает событие DataConsumer
один раз присоединяет свой метод-обработчик и не удаляет его, пока экземпляр не будет собран сборщиком мусора.
Вот странная часть;Когда я присоединяю отладчик к программному обеспечению в его поврежденном состоянии, я вижу, что переменная evt
в OnDataReady()
ссылается на экземпляр EventHandler
и не является нулевой.На самом деле он вызывает BeginInvoke, но метод HandleDataReady
никогда не вводится.Отладчик показывает, что свойство Method базового класса EventHandler
имеет значение null.Кажется, я не могу понять, как возможно, что EventHandler
изменяется.
(Первый) вопрос:
Что может вызвать остановку события в приведенном выше кодевызывается после нескольких часов работы?
My Best Guess:
Может ли что-то совершенно не связанное с моим приложением повредить память для EventHandler
?Я использую как нативные, так и управляемые библиотеки c ++.
Обновление:
Мое лучшее предположение оказалось маловероятным, так как я провел несколько других тестов, которые убедительно доказывают, что нативныйбиблиотеки не протекают и не повреждают память.
После повторного воспроизведения проблемы с ведением журнала я вижу, что событие не останавливается полностью, а вызывается с интервалом ~ 19 часов!Очевидно, что в делегате обработчика выполняется длительная операция или блокировка.
Чтобы быть уверенным, что это мой код, а не .NET, у меня есть обновленный вопрос ...
The (Второй) Вопрос:
Есть ли какое-либо поведение, встроенное в .NET (4.5) или его сборщик мусора, который может блокировать вызов EventHandler?