Um ehrlich zu sein, blicke ich noch nicht durch deine Invoking Sache ganz durch. Mein Bauch sagt, dass das so nicht gehen kann. Ich würde es eher so machen:
Code:
delegate void JumpToMainThread(Control c);
private void MainThreadAction(Control c)
{
if(this.InvokeRequired)
{
JumpToMainThread jumper = new JumpToMainThread(MainThreadAction);
jumper.Invoke(this, new object[]{ c });
return;
}
ModifyControl(c);
}
private void ModifyControl(Control c)
{
// mach was du willst
}
Die Sache ist die, dass das Invoke u.U. nicht sofort beim ersten Mal im richtigen Thread landet. Somit muss man immer weiter Invoke ausführen, bis der eigentliche Hauptthread getroffen wird. In deinem Beispiel würde ich es aber so lesen, das du nur 1x Invoke aufrufst und dann deine Aktionen in dem entsprechenden Thread ausführst, was natürlich bei mehreren Threads gnadenlos schief gehen wird.
Zum Thema Thread und Join würde ich auch etwas anderes machen.
Code:
private readonly object synchronizer = new object();
private void MyThread()
{
System.Threading.Monitor.Enter(synchronizer);
//
// mach was du willst (ist sowieso threadsafe)
//
System.Threading.Monitor.Exit(synchronizer);
}
private void OnLoad(EventArgs e)
{
System.Threading.Monitor.Enter(synchronizer);
//
// mach auch was du willst (ist sowieso threadsafe)
//
System.Threading.Monitor.Exit(synchronizer);
}
Das Ganze hat dann folgendes Verhalten, wenn der Thread VOR dem OnLoad gestartet wurde, dann wartet OnLoad solange bis der Thread seine Arbeit getan hat. Wenn der Thread während OnLoad gestartet wird, dann wartet er bis OnLoad fertig ist. Wenn der Thread nach OnLoad gestartet wurde, ist es eh unwichtig, da die beiden nicht mehr kollidieren können. Die Monitor Klasse benötigt immer ein Objekt anhand dessen es erkennen kann ob gewartet werden muss oder nicht. Um den Overhead klein zu halten wird hier die Superdupper-Basis-Klasse Object verwendet. Das readonly in der Deklaration von synchronizer setze ich um sicherzustellen, das ich nicht auf die Idee komme jemals dieses Objekt durch ein anderes Objekt zu ersetzen, weil dann die Synchronisierung hinfällig ist.
Viel Erfolg
Rossibaer
EDIT: Mir fiel gerade noch ein, dass du die Sachen zwischen den Monitor.Enter bzw Exit-Aufrufen relativ kurz und bündig halten solltest um nicht unnötig lange Wartezeiten der Threads zu provozieren. Theoretisch ist es egal, jedoch macht dann das Threading auch wenig Sinn, wenn der eine Thread ewig lang auf die Freigabe durch den anderen Thread wartet. Da kannst du ja auch gleich in einem Thread bleiben. Ebenso sind lokale Variablen in der Threadmethode deine wahren Freunde und der Zugriff auf Klassen- bzw. Objektvariablen eher wenig oder selten zu verwenden. Das wird dir ne Menge Kopfzerbrechen sparen.
EDIT2: Zu deinem Code: du erzeugst zuerst einen Refetch-Thread mit hoher Priorität, der Invoke aufruft? Unmittelbar nachdem der Thread gestartet wurde, wartet dein Hauptthread mit Join() darauf, das der Refetch-Thread seine Arbeit abgeschlossen hat? Ebenso macht dein Invoking (ReFetch-Thread)seinerseits wieder einen Rücksprung in den Hauptthread über InvokeRequired und Invoke. Kommts da nicht zum Deadlock? Ich hätte jetzt eher gedacht das du den Refetch-Thread anstößt der dein Resultset füllt, dann parallel weiter mit anderen Init-Sachen im Hauptthread deine Hauptmaske beackerst und zum Schluß mit Join wartest bis das Refetch fertig ist um dann abschließend noch paar Updates der Maske/Controls im Hauptthread nachzuführen.