Вопрос

В системе сбора цифрового сигнала часто данные передаются наблюдателю в системе одним потоком.

пример из Википедия/Observer_pattern:

foreach (IObserver observer in observers)
    observer.Update(message);

Когда , например ,действие пользователя, например, изграфический поток требует, чтобы поток данных прекратился, вы хотите разорвать соединение субъект-наблюдатель и даже полностью избавиться от наблюдателя.

Можно возразить:вы должны просто остановить источник данных и дождаться значения sentinel, чтобы удалить соединение.Но это привело бы к большей задержке в системе.

Конечно, если поток перекачки данных только что запросил адрес наблюдателя, он может обнаружить, что отправляет сообщение уничтоженному объекту.

Создал ли кто-нибудь "официальный" шаблон проектирования, противодействующий этой ситуации?Разве они не должны этого делать?

Это было полезно?

Решение

Если вы хотите, чтобы источник данных всегда находился на безопасной стороне параллелизма, у вас должен быть хотя бы один указатель, который всегда безопасен для его использования.Таким образом, объект Observer должен иметь срок службы, который не заканчивается раньше срока службы источника данных.

Это можно сделать, только добавив наблюдателей, но никогда не удаляя их.Вы могли бы попросить каждого наблюдателя не выполнять основную реализацию самостоятельно, а делегировать эту задачу объекту ObserverImpl.Вы блокируете доступ к этому объекту impl.В этом нет ничего особенного, это просто означает, что пользователь, отписавшийся от GUI, будет заблокирован на некоторое время, если наблюдатель занят использованием объекта ObserverImpl.Если отзывчивость графического интерфейса будет проблемой, вы можете использовать какой-нибудь механизм параллельной очереди заданий с включенным в него заданием отмены подписки.( как postMessage в Windows )

При отказе от подписки вы просто заменяете основную реализацию фиктивной реализацией.Опять же, эта операция должна захватить блокировку.Это действительно привело бы к некоторому ожиданию источника данных, но поскольку это всего лишь [замена указателя блокировки - разблокировка], вы могли бы сказать, что это достаточно быстро для приложений реального времени.

Если вы хотите избежать укладки объектов Observer, которые просто содержат фиктивный объект, вам нужно выполнить какую-то бухгалтерию, но это может сводиться к чему-то тривиальному, например, объекту, содержащему указатель на нужный ему объект Observer из списка.

Оптимизация :Если вы также сохраняете реализации (реальную + фиктивную) такими же активными, как и сам Наблюдатель, вы можете сделать это без фактической блокировки и использовать что-то вроде InterlockedExchangePointer для замены указателей.Наихудший сценарий :вызов делегирования продолжается, пока указатель заменяется -> ничего страшного, все объекты остаются живыми, и делегирование может продолжаться.Следующий делегирующий вызов будет направлен на новый объект реализации.( За исключением каких - либо новых обменов , конечно )

Другие советы

Вы могли бы отправить сообщение всем наблюдателям, информирующим их о завершении работы источника данных, и позволить наблюдателям удалить себя из списка.

В ответ на комментарий, реализация шаблона субъект-наблюдатель должна допускать динамическое добавление / удаление наблюдателей.В C # система событий представляет собой шаблон субъект / наблюдатель, в который наблюдатели добавляются с помощью event += observer и удален с помощью event -= observer.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top