1

In einem digitalen Signalerfassungssystem werden Daten oft in einem Beobachter im System um einen Thread verschoben.Entwurfsmuster für Multithread-Beobachter

Beispiel aus Wikipedia/Observer_pattern:

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

Wenn z.B. eine Benutzeraktion von z.B. Ein GUI-Thread erfordert, dass die Daten nicht mehr fließen, dass Sie die Subjekt-Beobachter-Verbindung unterbrechen und sogar den Beobachter insgesamt entsorgen wollen.

Man kann argumentieren: Sie sollten nur die Datenquelle stoppen, und warten Sie auf einen Sentinel-Wert der Verbindung zu entsorgen. Aber das würde mehr Latenz im System verursachen.

Natürlich, wenn die Daten Pump Thread ist nur für die Adresse des Betrachters gefragt, könnte es findet es eine Nachricht an ein zerstörtes Objekt sendet.

Hat jemand ein "offizielles" Designmuster erstellt, das dieser Situation entgegenwirkt? Sollten sie nicht?

+0

Ich bin hier irgendwie verwirrt. Was versuchst du zu vermeiden?Sprechen Sie über einen Fall, in dem ein Thread die Registrierung eines Beobachters aufheben möchte, aber ein anderer Thread über alle Beobachter iteriert? –

+0

Ich weiß nicht, welche konkrete Klasse Sie implementieren "IObserver" aber wenn "Update" bedeutet "tun, was Sie tun müssen, um sich mit einer Datenquelle auf dem neuesten Stand zu bringen", dann wäre das richtige Verhalten für ein Objekt angeordnet schweigend nichts tun. Wenn jedem Beobachter ein Objekt zugeordnet ist, das angibt, ob Subskriptionen weiterhin empfangen werden sollen und ob das pumpende Objekt ein Flag hat, das anzeigt, ob solche Objekte seit dem letzten Scanvorgang eine Abmeldung angefordert haben, kann der pumpende Thread Objekte für Subskriptionen abfragen wenn gebraucht. – supercat

Antwort

2

Wenn Sie die Datenquelle haben wollen auf der sicheren Seite der Parallelität immer sein, sollten Sie mindestens einen Zeiger haben, die immer für ihn sicher zu bedienen ist. Das Observer-Objekt sollte also eine Lebensdauer haben, die nicht vor der der Datenquelle endet.

Dies kann getan werden, indem nur Beobachter hinzugefügt, aber nie entfernt werden. Sie können festlegen, dass jeder Beobachter die Kernimplementierung nicht selbst ausführt, sondern diese Aufgabe an ein ObserverImpl-Objekt delegiert. Sie sperren den Zugriff auf dieses Impl-Objekt. Das ist keine große Sache, es bedeutet nur, dass der GUI-Abbesteller für eine kurze Zeit blockiert wäre, wenn der Beobachter das ObserverImpl-Objekt verwendet. Wenn die Reaktionsfähigkeit der Benutzeroberfläche ein Problem darstellen würde, können Sie eine Art von Job-Queue-Mechanismus gleichzeitig verwenden, auf den ein Abmeldeauftrag angewendet wird. (Wie in Windows Postmessage)

Wenn abzumelden, ersetzen Sie einfach den Kern Implementierung für eine Dummy-Implementierung. Auch diese Operation sollte das Schloss greifen. Dies würde in der Tat ein wenig Warten auf die Datenquelle bedeuten, aber da es nur ein [Sperren - Zeiger - Austausch - Entsperren] ist, könnte man sagen, dass dies für Echtzeitanwendungen schnell genug ist.

Wenn Sie Observer-Objekte, die nur einen Dummy enthalten, nicht stapeln wollen, müssen Sie eine Art Buchführung durchführen, aber dies könnte auf etwas Triviales wie ein Objekt mit einem Zeiger auf das Observer-Objekt aus der Liste hinauslaufen .

Optimierung: Wenn Sie auch die Implementierungen (die echte + der Dummy) so lange am Leben halten wie der Observer selbst, können Sie dies ohne eine tatsächliche Sperre tun, und etwas wie InterlockedExchangePointer verwenden, um die Zeiger zu tauschen. Worst-Case-Szenario: Der Delegierungsaufruf wird ausgeführt, während der Zeiger ausgetauscht wird -> keine große Sache alle Objekte bleiben am Leben und die Delegierung kann fortgesetzt werden. Nächster Delegierungsaufruf wird für ein neues Implementierungsobjekt sein. (Barrieren natürlich keine neuen Swaps)

0

Sie können eine Mitteilung an alle Beobachter schicken sie die Datenquelle beendet wird informiert und lassen die Beobachter selbst aus der Liste entfernen.

Als Reaktion auf den Kommentar, sollte die Umsetzung des Themas-Beobachter-Muster für dynamische Hinzufügen/Entfernen von Beobachtern ermöglichen. In C# ist das Ereignissystem ein Subjekt-/Beobachtermuster, bei dem Beobachter unter Verwendung von event += observer hinzugefügt und unter Verwendung von event -= observer entfernt werden.

+0

In der Tat, aber die Idee ist, dass die Datenquelle läuft (da es z. B. eine riesige Setup-Zeit hat ...), und Sie sich im laufenden Betrieb abmelden. – xtofl