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.
Könnte es sein, dass Ihre Taskvariable t vor dem Abschluss den Gültigkeitsbereich verlässt? –