2 Stimmen

Was ist ein Muster, um zwei "tiefe" Teile eines Multi-Thread-Programms miteinander kommunizieren zu lassen?

Ich habe dieses generelle Problem beim Design, Refactoring oder "Triage":

Ich habe eine bestehende Multithreading-C++-Anwendung, die für Daten mit einer Reihe von Plugin-Bibliotheken sucht. Mit der aktuellen Suchschnittstelle erhält ein bestimmtes Plugin einen Suchstring und einen Zeiger auf ein QList-Objekt. Das Plugin läuft auf einem anderen Thread und durchsucht verschiedene Datenquellen (lokal und im Internet) und fügt die gewünschten Objekte der Liste hinzu. Wenn das Plugin zurückkehrt, fügt das Hauptprogramm, das sich immer noch auf dem separaten Thread befindet, diese Daten in den lokalen Datenspeicher ein (mit weiterer Verarbeitung), wobei dieser Einfügepunkt durch einen Mutex geschützt wird. So kann jedes Plugin Daten asynchron zurückgeben.

Die QT-base Plugin-Bibliothek basiert auf Message Passing. Es gibt eine ganze Reihe von Plugins, die bereits für die Anwendung geschrieben und getestet wurden, und sie funktionieren recht gut.

Ich möchte einige weitere Plugins schreiben und die bestehende Anwendung nutzen.

Das Problem ist, dass die neuen Plugins mehr Informationen von der Anwendung benötigen. Sie müssen bei ihrer Suche zeitweise auf den lokalen Datenspeicher selbst zugreifen. Um diesen zu erhalten, bräuchten sie also direkten oder indirekten Zugriff sowohl auf das Hash-Array, in dem die Daten gespeichert sind, als auch auf den Mutex, der den Mehrfachzugriff auf den Speicher überwacht. Ich nehme an, dass der Zugriff durch Hinzufügen einer zusätzlichen Methode in einem "Katalog"-Objekt gekapselt werden würde.

Ich sehe drei Möglichkeiten, diese neuen Plugins zu schreiben.

  1. Wenn Sie ein Plugin laden, übergeben Sie ihnen einen Zeiger auf meinen "Katalog" an die Start. Dies wird eine zusätzliche, "unsichtbare" Schnittstelle für die neuen Plugins. Dies scheint schnell, einfach, völlig falsch im Sinne von OO, aber Ich kann nicht erkennen, wo die zukünftigen Probleme liegen könnten.

  2. Hinzufügen einer Methode/Nachricht zur bestehende Schnittstelle, damit ich eine zweite Funktion, die sein könnte für die neue Plugin-Bibliothek aufgerufen werden kann

  3. Umgestaltung der Plugin-Schnittstelle. Dies scheint laut OO "das Beste" zu sein, könnte andere zusätzliche Vorteile haben, aber würde alle Arten von umschreiben.

Meine Fragen lauten also

A. C konkrete Gefährdungen der Option 1?

B. Gibt es ein bekanntes Muster, das auf diese Art von Problem passt?

Bearbeiten1:

Eine typische Funktion zum Aufruf der Plugin-Routinen sieht so aus:

elsewhere(spec){
    QList<CatItem> results;
    plugins->getResult(spec, &results);
    use_list(results);
}

...
void PluginHandler::getResults(QString* spec, QList<CatItem>* results)
{
    if (id->count() == 0) return;
    foreach(PluginInfo info, plugins) {
        if (info.loaded)
            info.obj->msg(MSG_GET_RESULTS, (void*) spec, (void*) results);
    }
}

Das zieht sich wie ein roter Faden durch den Code. Ich würde ihn lieber erweitern, als ihn zu zerstören.

4voto

jalf Punkte 235501

Warum ist es "völlig falsch nach OO"? Wenn Ihr Plugin Zugriff auf dieses Objekt benötigt und es keine Abstraktion verletzt, die Sie bewahren wollen, ist es die richtige Lösung.

Für mich sieht es so aus, als hätten Sie Ihre Abstraktionen in dem Moment zerstört, als Sie entschieden, dass Ihr Plugin Zugriff auf die Liste selbst benötigt. Sie gerade gesprengt Ihre gesamte Anwendung Architektur. Sind Sie sicher, dass Sie Zugriff auf die tatsächliche Liste selbst benötigen? Und warum? Was brauchen Sie von ihr? Können diese Informationen auf eine sinnvollere Weise bereitgestellt werden? Eine, die 1) nicht die Konkurrenz um eine gemeinsam genutzte Ressource erhöht (und das Risiko von subtilen Multithreading-Fehlern wie Race Conditions und Deadlocks erhöht), und 2) nicht die Architektur der restlichen Anwendung untergräbt (die speziell eine Trennung zwischen der Liste und ihren Clients beibehält, um Asynchronität zu ermöglichen)

Wenn Sie denken, dass es schlechtes OO ist, dann liegt es an dem, was Sie im Grunde versuchen zu tun (die grundlegende Architektur Ihrer Anwendung zu verletzen), nicht an wie Sie tun es.

1voto

Vinko Vrsalovic Punkte 252104

Nun, Option 1 ist letzten Endes Option 3. Sie entwerfen Ihre Plugin-API neu, um zusätzliche Daten von der Hauptanwendung zu erhalten.

Es ist ein einfaches Redesign, das, solange der "Katalog" gut implementiert ist und jedes Implementierungsdetail Ihres Hash- und Mutex-Backing-Stores verbirgt, nicht schlecht ist und den Zweck gut genug erfüllen kann IMO.

Wenn nun der Katalog Implementierungsdetails preisgibt, sollten Sie besser Nachrichten verwenden, um den Speicher abzufragen und Antworten mit den benötigten Daten zu erhalten.

1voto

Bill K Punkte 61074

Entschuldigung, ich habe Ihre Frage gerade dreimal gelesen und ich glaube, meine Antwort war vielleicht zu einfach.

Ist Ihr "Katalog" ein eigenständiges Objekt? Wenn nicht, könnten Sie ihn als eigenes Objekt einpacken. Der Katalog sollte völlig sicher sein (auch thread-sicher) - oder besser noch unveränderlich.

Wenn dies geschehen ist, wäre es ein vollkommen gültiges OO, Ihren Katalog an die neuen Plugins zu übergeben. Wenn Sie darüber besorgt sind, sie durch viele Schichten zu führen, können Sie eine Fabrik für den Katalog erstellen.

Tut mir leid, wenn ich immer noch etwas missverstehe, aber ich sehe nichts Falsches an diesem Ansatz. Wenn Ihr Katalog jedoch ein Objekt ist, das sich Ihrer Kontrolle entzieht, wie z. B. ein Datenbankobjekt oder eine Sammlung, dann MÜSSEN Sie es wirklich in etwas kapseln, das Sie mit einer schönen, sauberen Schnittstelle kontrollieren können.

Wenn Ihr Katalog von vielen Teilen Ihres Programms verwendet wird, könnten Sie eine Fabrik in Betracht ziehen (die in ihrer einfachsten Form zu einem Singleton degradiert). Mit einer Fabrik sollten Sie in der Lage sein, Ihren Katalog mit einem Catalog.getType("Clothes"); oder was auch immer aufzurufen. Auf diese Weise geben Sie das gleiche Objekt an jeden aus, der es haben möchte, ohne es weiterzugeben.

(dies ist sehr ähnlich zu einem Singleton, übrigens, aber Kodierung es als eine Fabrik erinnert Sie daran, dass es fast sicher mehr als eine--auch daran denken, eine Catalog.setType("Clothes", ...); für die Prüfung zu ermöglichen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X