Question

Dans un système d'acquisition de signal numérique, les données sont souvent transmises à un observateur du système par un seul thread.

exemple tiré de Wikipedia / Observer_pattern :

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

Quand par ex. une action utilisateur, par exemple un fil d'interface graphique nécessite que les données cessent de circuler, vous souhaitez rompre la connexion sujet-observateur et même disposer de l'observateur dans son ensemble.

On peut soutenir que vous devez simplement arrêter la source de données et attendre une valeur sentinel pour disposer de la connexion. Mais cela entraînerait plus de latence dans le système.

Bien sûr, si le thread de pompage de données vient de demander l’adresse de l’observateur, il se peut qu’il envoie un message à un objet détruit.

Quelqu'un a-t-il créé un motif de conception "officiel" contrant cette situation? Ne devraient-ils pas?

Était-ce utile?

La solution

Si vous souhaitez que la source de données soit toujours du côté sans danger de la concurrence, vous devez disposer d'au moins un pointeur qu'il peut toujours utiliser en toute sécurité. L’objet Observer doit donc avoir une durée de vie qui n’est pas terminée avant celle de la source de données.

Cela peut être fait en ajoutant seulement des observateurs, mais en ne les supprimant jamais. Vous pouvez demander à chaque observateur de ne pas effectuer l’implémentation principale elle-même, mais de le déléguer à un objet ObserverImpl. Vous verrouillez l'accès à cet objet impl. Ce n'est pas grave, cela signifie simplement que le désabonné de l'interface graphique serait bloqué pendant un certain temps si l'observateur est occupé à utiliser l'objet ObserverImpl. Si la réactivité de l’interface graphique pose un problème, vous pouvez utiliser un mécanisme de file d’attente de travail simultané sur lequel un travail de désabonnement est appliqué. (comme PostMessage dans Windows)

Lorsque vous vous désabonnez, vous remplacez simplement l'implémentation principale par une implémentation factice. Encore une fois cette opération devrait attraper le verrou. Cela introduirait certes une attente pour la source de données, mais comme il s’agit d’un simple [échange - verrouillage de pointeur - déverrouillage], on pourrait dire que cela est assez rapide pour les applications en temps réel.

Si vous voulez éviter d'empiler des objets Observer contenant uniquement un mannequin, vous devez effectuer une sorte de comptabilité, mais cela pourrait se résumer à quelque chose de trivial, comme un objet contenant un pointeur sur l'objet Observer dont il a besoin dans la liste.

Optimisation: Si vous conservez également les implémentations (réelle et factice) aussi longtemps que l'observateur lui-même, vous pouvez le faire sans verrou réel et utiliser quelque chose comme InterlockedExchangePointer pour échanger les pointeurs. Dans le pire des cas: un appel en cours de délégation se produit lorsque le pointeur est échangé - > pas grave, tous les objets restent en vie et la délégation peut continuer. Le prochain appel de délégation concernera un nouvel objet d'implémentation. (Sauf tout nouvel échange bien sûr)

Autres conseils

Vous pouvez envoyer un message à tous les observateurs pour les informer de la fin de la source de données et laisser les observateurs se retirer de la liste.

En réponse au commentaire, la mise en œuvre du modèle sujet-observateur devrait permettre l’ajout / le retrait dynamique d’observateurs. En C #, le système d’événements est un modèle sujet / observateur dans lequel les observateurs sont ajoutés avec événement + = observateur et supprimés avec événement - = observateur .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top