Что может заставить это событие перестать вызываться? - PullRequest
0 голосов
/ 15 февраля 2019

Проблема:

Я использую асинхронную обработку событий в классе, который вызывает событие примерно 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?

...