2010-12-05 3 views
2

Ich versuche, ein Plugin-Typ-System zu machen. Ich habe in der Vergangenheit etwas in diese Richtung gemacht, wo alle Plugins im Hauptthread ausgeführt werden, was zu Problemen führt, wenn die Plugins sehr lange brauchen. Also dachte ich, ich würde die entsprechenden Methoden in jedem Plugin mit Tasks ausführen.Aufgabe (oder Thread) erfordert Warten oder Verbinden zur Arbeit

Ich habe ein Hauptprogramm, das jedes Plugin mit Assembly.LoadFile lädt und dann auf Befehle reagiert, die ein Benutzer eingibt. Wenn einer dieser Befehle von einem Plugin gehandhabt wird (die Plugins melden, welche Befehle sie behandeln, fragt das Hauptprogramm, wann sie sie lädt), wird mein Programm eine Methode im Plugin in einer eigenen Task starten.

Jedes Plugin implementiert auch ein Ereignis, das verwendet wird, wenn Daten an das Hauptprogramm zur Ausgabe gesendet werden sollen. Das Hauptprogramm fügt diesem Ereignis einen Handler bei, wenn es jedes Plugin lädt.

Die ProcessCommand-Methode des Plugins führt die erforderliche Arbeit aus, löst das OnOutput-Ereignis aus und wird dann beendet.

Dies ist ein sehr einfaches Plugin:

public override void ProcessCommand(PluginCommand Command, PluginParameters Parameters, PluginContext Context) 
{ 
    OnOutputGenerated(this,"Hello from Plugin A"); 
} 

Das mit dem ersten Plugin funktionierte gut ich gemacht. Also habe ich einen anderen erstellt, der genau den gleichen Code verwendet und nur "Hallo von Plugin A" zu "Hallo von Plugin B" geändert hat.

Plugin A funktioniert immer. Wenn ich den entsprechenden Befehl im Hauptprogramm ausfühle, läuft es und sagt Hallo von Plugin A. Großartig.

Das Problem ist: Plugin B führt vielleicht einen in 30 Versuchen aus. Ich habe jedoch festgestellt, dass, wenn das Plugin auf folgende Weise aufrufen, es funktioniert jedes Mal: ​​

Task t = Task.Factory.StartNew(() => Plugin.ProcessCommand(cmd, Params, Context)); 
t.Wait(100); 

Gibt es einen technischen Grund, warum dies helfen könnte? Ich habe so ziemlich alles durchgelesen http://www.albahari.com/threading/ versucht, die Dinge herauszufinden, aber ich hatte kein Glück.

Es ist erwähnenswert, dass ich dies auch mit Threads gemacht habe, mit dem gleichen Problem.

Thread t = new Thread(() => Plugin.ProcessCommand(cmd, Params, Context)); 
t.Start(); 

Hinzufügen:

t.Join(100); 

"fixiert" es.

Aktualisiert

ich alles vereinfacht habe. Ich habe ein neues Projekt erstellt, das den gesamten Code entfernt, der nichts mit den Fehlern zu tun hat.

foreach (string File in Directory.GetFiles(PluginDir, "*.dll")) { 

    try { 

     IPlugin Plugin = PluginManager.LoadPlugin(File); 
     Plugin.OnOutputGenerated += new PluginOutputEvent(Plugin_OnOutputGenerated); 

    } catch (Exception ex) { 

    } 

} 

// main loop 

string Line = Console.ReadLine(); 

foreach (IPlugin Plugin in PluginManager.LoadedPlugins) { 

    foreach (PluginCommand cmd in Plugin.GetCommands()) { 

     if (cmd.Command.Equals(Line, StringComparison.InvariantCultureIgnoreCase)) { 

      PluginParameters Params = cmd.TryParseParameters(ParamString); 
      Task t = Task.Factory.StartNew(() => Plugin.ProcessCommand(cmd, Params, Context)); 

     } 

    } 

} 

// output handler 

static void Plugin_OnOutputGenerated(IPlugin Plugin, string OutputString) { 

    Console.WriteLine("Output: " + OutputString); 

} 

Das Hauptproblem hat sich geändert. Zuvor funktionierte eines der Plugins die meiste Zeit nicht. Stellen Sie sich zwei Plugins vor.

A
* Hat einen Befehl Plugin: Commanda
* Befehl OnOutputGenerated Ereignis mit der Zeichenfolge "Hallo von Plugin A"

Plugin B
* Hat einen Befehl löst: CommandB
* Command löst OnOutputGenerated-Ereignis mit der Zeichenfolge "Hello from Plugin B" aus

Wenn ich dieses neue Projekt ausführen, das ich gemacht habe, und den Befehl "CommandA" ausgeben, wird es "Hallo von Plugin B" zurückgeben. Es macht weiter so, bis ich tatsächlich "CommandB" ausstelle. Sobald ich das getan habe, druckt es "Hallo von Plugin B" (wie es sollte). Wenn ich dann wieder "CommandA" ausstelle, gibt es "Hallo von Plugin A" (wie es ursprünglich hätte sein sollen).

Wenn ich hinzufügen

t.Wait(100); 

es ist behoben. Es scheint immer noch etwas mit der Aufgabe zu tun zu haben, aber ich weiß nicht wie. Es scheint, dass meine Logik ansonsten in Ordnung ist. Ich kann nicht sehen, wie es Plugin B ausführen würde, wenn es Plugin A ausführen soll, oder umgekehrt.

+0

Könnte es sein, dass Ihre Taskvariable t vor dem Abschluss den Gültigkeitsbereich verlässt? –

Antwort

2

Es klingt wie ohne die Wait oder Join, Ihr Hauptprogramm einfach beendet, bevor der angeforderte Task Code eine Chance hat zu laufen. Wenn die Task Logik im Hauptthread inline wäre, hätte dies impliziert, dass der Hauptthread warten würde, während der Code ausgeführt wird. Jetzt haben Sie es in einen separaten Thread verschoben, Sie müssen eine explizite Wartezeit hinzufügen, damit alle Task Sie starten können, um abzuschließen (vielleicht mit einer Zeitüberschreitung, falls etwas schief geht).

Es ist möglich, dass, selbst wenn Sie nicht warten, ein Task gelegentlich beendet werden kann - das wird unbestimmt sein, abhängig vom Timing in jedem einzelnen Lauf.

Können Sie klären, was passiert im Haupt-Thread ohne Wait oder Join?

+0

In jeder Hinsicht ist das Hauptprogramm eine große Schleife mit einer Console.ReadLine(), einem Abschnitt, um zu analysieren, was getippt wird, und dann der Abschnitt, der das Plugin aufruft, wenn der Benutzer etwas passendes zu einem Plugin eingegeben hat. Die Absicht ist, dem Benutzer zu ermöglichen, eine Anzahl von potentiell zeitaufwendigen Aufgaben auszulösen, ohne auf das Programm warten zu müssen, um wieder zu Console.ReadLine zu gelangen. – Neil

+0

Danke - also könnten deine Abschluss-Event-Handler den Bereich verlassen, wie von @Jakob in Kommentaren bemerkt, wenn du nicht wartest/beitrittst? –

+0

Wirklich nicht sicher in diesem Stadium. Es sieht nicht so aus, aber ich versuche verschiedene Dinge. Ich werde mehr Code bereitstellen, wenn ich genau herausgefunden habe, was selbst passiert! Drei verschiedene Bugs im Moment. Ich versuche herauszufinden, was eigentlich relevant ist. – Neil

Verwandte Themen