В системе сбора цифровых сигналов данные часто передаются наблюдателю в системе одним потоком.
пример из Википедия / Observer_pattern:
foreach (IObserver observer in observers)
observer.Update(message);
Когда, например, действие пользователя, например, GUI-поток требует, чтобы данные перестали передаваться, вы хотите разорвать соединение субъект-наблюдатель и даже полностью избавиться от наблюдателя.
Кто-то может возразить: вам нужно просто остановить источник данных и дождаться контрольного значения, чтобы удалить соединение. Но это повлечет за собой большую задержку в системе.
Конечно, если поток перекачки данных только что запросил адрес наблюдателя, он может обнаружить, что отправляет сообщение уничтоженному объекту.
Создал ли кто-нибудь «официальный» шаблон дизайна для противодействия этой ситуации? Разве они не должны?
Я не знаю, какой конкретный класс у вас реализует IObserver, но если «Обновить» означает «делать все, что вам нужно, чтобы быть в курсе последних событий с источником данных», то правильным поведением для удаленного объекта будет молчаливое выполнение ничего. Если есть объект, связанный с каждым наблюдателем, который указывает, следует ли ему продолжать получать подписки, и если у перекачивающего объекта есть флаг, указывающий, запрашивали ли какие-либо такие объекты отписку с момента последнего сканирования, поток перекачки может опрашивать объекты на предмет отказа от подписки. при необходимости.





Вы можете отправить сообщение всем наблюдателям, информируя их о прекращении работы источника данных, и позволить наблюдателям удалить себя из списка.
В ответ на комментарий реализация шаблона субъект-наблюдатель должна позволять динамическое добавление / удаление наблюдателей. В C# система событий - это шаблон субъект / наблюдатель, в котором наблюдатели добавляются с помощью event += observer и удаляются с помощью event -= observer.
Действительно, но идея заключается в том, что источник данных продолжает работать (поскольку у него, например, огромное время настройки ...), и вы отказываетесь от подписки на лету.
Если вы хотите, чтобы источник данных всегда был в безопасности от параллелизма, у вас должен быть хотя бы один указатель, который всегда будет безопасным для его использования. Таким образом, объект Observer должен иметь время жизни, которое не заканчивается раньше, чем у источника данных.
Это можно сделать, только добавляя наблюдателей, но никогда не удаляя их. Вы можете сделать так, чтобы каждый наблюдатель сам не выполнял основную реализацию, а делегировал эту задачу объекту ObserverImpl. Вы блокируете доступ к этому объекту impl. В этом нет ничего страшного, это просто означает, что пользователь, отписавшийся от GUI, будет заблокирован на некоторое время в случае, если наблюдатель занят использованием объекта ObserverImpl. Если отзывчивость графического интерфейса будет проблемой, вы можете использовать какой-то параллельный механизм очереди заданий с отправкой на него задания отказа от подписки. (как PostMessage в Windows)
При отказе от подписки вы просто заменяете базовую реализацию фиктивной. Опять же, эта операция должна захватить блокировку. Это действительно привело бы к некоторому ожиданию источника данных, но поскольку это всего лишь [блокировка - замена указателя - разблокировка], можно сказать, что этого достаточно для приложений реального времени.
Если вы хотите избежать наложения объектов Observer, которые просто содержат фиктивную информацию, вам придется провести какую-то бухгалтерию, но это может сводиться к чему-то тривиальному, например, к объекту, содержащему указатель на объект Observer, который ему нужен из списка.
Оптимизация: Если вы также сохраните реализации (настоящая + фиктивная) в живых до тех пор, пока сам Observer, вы можете сделать это без фактической блокировки и использовать что-то вроде InterlockedExchangePointer для замены указателей. Худший сценарий: вызов делегирования происходит, пока указатель заменен -> ничего страшного, все объекты остаются в живых, и делегирование может продолжаться. Следующий вызов делегирования будет направлен на новый объект реализации. (Разумеется, за исключением любых новых свопов)
Я здесь немного запутался. Чего вы пытаетесь избежать? Вы говорите о случае, когда один поток хочет отменить регистрацию наблюдателя, но другой поток выполняет итерацию по всем наблюдателям?