1

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

пример из Wikipedia/Observer_pattern:

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

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

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

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

Кто-нибудь создал «официальный» шаблон дизайна, противостоящий этой ситуации? Разве они не должны?

+0

Я здесь немного смущен. Чего вы пытаетесь избежать?Вы говорите о случае, когда один поток хочет отменить регистрацию наблюдателя, но другой поток выполняет итерацию над всеми наблюдателями? – 2008-09-19 16:43:18

+0

Я не знаю, какой конкретный класс вы используете «IObserver», но если «Обновить» означает «сделайте все, что вам нужно, чтобы обновить источник данных», тогда правильное поведение для объекта тихо ничего не делать. Если есть объект, связанный с каждым наблюдателем, который указывает, должен ли он продолжать получать подписки, и если у объекта перекачки есть флаг, указывающий, запрашивали ли какие-либо такие объекты отмену подписки с момента последнего сканирования, поток накачки может опросить объекты для непокрытий при необходимости. – supercat 2013-01-27 22:17:17

ответ

2

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

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

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

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

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

0

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

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

Смежные вопросы