Synchron- / Blocking Application.Invoke () für GTK #
-
19-09-2019 - |
Frage
Leider Application.Invoke()
ist asynchron:
private string ThreadFunction(int i)
{
string result = null;
Gtk.Application.Invoke(delegate
{
OutputStringToUserInterface("i = " + i.ToString());
result = GetStringFromUserInterface();
});
return result;
}
Das bedeutet, dass in diesem Beispiel ThreadFunction()
geht unmittelbar nach Application.Invoke()
Aufruf, was zu einem wahrscheinlich undefinierten Zustand des result
String. -. ThreadFunction()
wird schneller sein und wird mit dem alten Wert zurück (das heißt null
)
Dies ist eine Abhilfe ManualResetEvent
mit Application.Invoke()
synchron zu machen:
private string ThreadFunction(int i)
{
string result = null;
using (var ev = new ManualResetEvent(false))
{
Gtk.Application.Invoke(delegate
{
OutputStringToUserInterface("i = " + i.ToString());
result = GetStringFromUserInterface();
ev.Set();
});
ev.WaitOne();
}
return result;
}
Auf diese Weise wartet ThreadFunction()
bis Application.Invoke()
zurückkehrt, wie es mit täte WinForms Control.Invoke () .
EDIT: Besserer Beispiel-Code
EDIT2: Fehlende using
Nun meine Frage: Gibt es eine bessere Lösung
Lösung
Nun ja, es gibt keinen Grund zu warten, bis die Delegierten den richtigen Rückgabewert zu erhalten auszuführen. Fix:
int result = i + 1;
Und es ist in Ordnung, die OutputStringToUserInterface () ausführt asynchron zu lassen, Sie unter der Annahme, rufen Sie nicht ThreadFunction () so oft, dass es den UI-Thread mit Anfragen überschwemmt.
Wenn Sie Ihr echter Code tatsächlich abhängig von einem Rückgabewert einer Funktion, die dann auf dem UI-Thread ausgeführt werden muß, nein, können Sie es nicht schneller. Klar, das ist etwas, das Sie wirklich zu vermeiden.
Andere Tipps
Sie können Ihren aktuellen Code in einen generischen Wrapper kapseln:
public static void GuiInvoke(Action action)
{
var waitHandle = new ManualResetEventSlim();
Gtk.Application.Invoke( (s,a) =>
{
action();
waitHandle.Set();
});
waitHandle.Wait();
}
public static void BeginGuiInvoke(Action action)
{
Gtk.Application.Invoke( (s,a) => {action();});
}