Шаблон проектирования для многопоточных наблюдателей - PullRequest
1 голос
/ 17 сентября 2008

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

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

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

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

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

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

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

Ответы [ 2 ]

2 голосов
/ 19 сентября 2008

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

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

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

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

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

0 голосов
/ 17 сентября 2008

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

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

...