Hallo liebe Community,
hab in eurem Board schon oft hilfreiche Tipps gefunden und melde mich nun auch mal selbst zu Wort =)
Und zwar ginge es um folgenden Code:
public void Attach(ClockObserver o)
{
lock(_lockThis)
{
_attachedObservers.Add(o);
}
}
public void Detach(ClockObserver o)
{
lock (_lockThis)
{
_attachedObservers.Remove(o);
}
}
public void FireUpdates(object drawInfo)
{
var e = (DrawInformations)drawInfo;
lock (_lockThis)
{
foreach (ClockObserver o in _attachedObservers)
o.Update(e);
}
}
Und zwar wird Attach beim Öffnen einer Form, Detach beim Schließen, und FireUpdates automatisch jede Sekunde aufgerufen.
Das Update führt zum Zeichnen einer selber geschriebenen Komponente.
Auf jeden Fall hängt sich mein Programm ab und zu auf, wenn ich eine Form schließe.
Jetzt ist meine Frage, sind meine lock's eventuell falsch gesetzt, kann man das aus diesem kleinen Codestück ablesen?
Danke schon im Voraus.
Greets
Mika
Hallo,
Auf jeden Fall hängt sich mein Programm ab und zu auf, wenn ich eine Form schließe. Machst Du die Updates über einem Timer?
Gruß, MarsStein
Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca
Hallo,
Kann es sein, dass du in der Update - Funktion der Form ein Invoke verwendest um dich dort mit dem GUI-Thread zu Synchronisieren?
Wenn ja, kann folgendes Szenario entstehen:
Thread A ... Gui - Thread.
Thread B ... Thread der Fire Updates aufruft.
greets
Kann es sein, dass du in der Update - Funktion der Form ein Invoke verwendest um dich dort mit dem GUI-Thread zu Synchronisieren?
Ja, ich lasse in der Update-Methode über Invoke mein Control refreshen, damit es neu gezeichnet wird (dauert zwischen 0 und 2 Millisekunden, das heißt, wenn jede Sekunde aktualisiert wird, darf es bei 50 Controlls kein Problem von wegen zu langer Refresh-Dauer geben) ...
Das heißt der Fehler rührt vom Invoke...
Jetzt wäre es noch irgendwie schön, wenn du vielleicht eine Lösung parat hättest xD
Weil ich eben noch eher neu bin in Multithreadprogrammierung und Threadsicherheit.
Greets und Danke
Mika
versuch mal statt Invoke mit BeginInvoke zu synchronisieren, da dies den aufrufenden Thread nicht blockiert.
Ich bin mir jetzt allerdings nicht 100%ig sicher, ob dies nicht wieder zu anderen Threadingprobs. durch das Schließen der Form kommen kann, da noch ein Update nach dem Schließen kommen kann.
versuch mal statt Invoke mit BeginInvoke zu synchronisieren, da dies den aufrufenden Thread nicht blockiert.
Ich bin mir jetzt allerdings nicht 100%ig sicher, ob dies nicht wieder zu anderen Threadingprobs. durch das Schließen der Form kommen kann, da noch ein Update nach dem Schließen kommen kann.
Du bist mein Held =)
Mit BeginInvoke gehts...
public void Update(DrawInformations e)
{
drawInformations = e;
if (this.InvokeRequired)
this.BeginInvoke(new UpdateMethod(this.Update), e);
else
this.Refresh();
}
Aber wie kann ich mir das mit BeginInvoke jetzt genau vorstellen? Der wartet dann also wieder sozusagen als eigenständiger Teil darauf, dass die Threads synchronisiert sind und blockiert nicht? Und ruft dann, wenn sie synchron sind, die Methode eben erneut auf...
Aber wenn in der Zeit, in der er nun darauf wartet, dass sie synchronisiert sind, könnte doch nun das Element gelöscht werden oder so, dann bekomme ich höchstwahrscheinlich eine ObjectDisposedException, oder?
EDIT: Okay, diesen Fehler hatte ich früher... Habe nun einfach einige Male ca. 50 Forms geöffnet und nach der Reihe geschlossen und konnte diese Exception nicht mehr beobachten. Ich hoffe es hat sich damit nun erledigt. =)
EDIT2: Habe nun alles durchdacht, hatte früher die lock's in Attach und Detach noch nicht. Wenn ich nun das Fenster schließe, rufe ich Detach mit seinen enthaltenen Controls auf. Damit ist eigentlich gewährleistet, dass sie entweder gleich gelöscht werden, oder sie so lange warten, bis alle neu gezeichnet wurden und dann gelöscht wurden. Also alles im grünen Berreich.
Ich bedanke mich noch einmal recht herzlich.
Greets Mika
Schau mal unter [FAQ] Controls von Thread aktualisieren lassen (Control.Invoke/Dispatcher.Invoke), dort ist das mit Invoke & BeginInvoke schön beschrieben, auch warum es bei Invoke zu einem Deadlock kommen kann.
Der Hauptunterschied ist, dass Invoke warted bist die Aktion im Gui-Thread abgeschlossen ist, und BeginInvoke dem Gui-Thread quasi sagt, mach mal die Aktion wenn du Zeit hast, und sofort weitermacht, ohne auf die Abarbeitung zu warten.
Danke, so umrisshaft wusste ich das meiste schon, zumindest der Hintergrund, warum Invoke verwendet werden muss.
Aber BeginInvoke war mir noch nicht bekannt.
Danke dir.
Hallo mika92,
warum verwendest du statt der Attach/Detach/FileUpdate-Mimik nicht besser ein eigenes Event? Siehe [FAQ] Eigenen Event definieren
herbivore
warum verwendest du statt der Attach/Detach/FileUpdate-Mimik nicht besser ein eigenes Event? Siehe
>
Aufgabe des Lehrers... Einmal nicht mit Events programmieren, sondern mal eher so wie in Java... Dadurch wird anscheinden "die Bindung auch nicht so stark"... Naja wenn er meint xD
Sorry, aber noch einmal zurück zu meinem Programm... Mir ist nun doch eine Schwachstelle aufgefallen.
Gehen wir nun davon aus, dass mein GUI-Thread grad ein bisschen beschäftigt ist und er auf mein BeginInvoke nicht sofort reagiert...
Angenommen ich schließe nun meine Form (dabei rufe ich Detach auf und entferne meine Componente von der Update-Liste, Invoke wurde aber noch immer nicht gemacht)... Und dann räumt der GarbageCollector meine Componente auf (ruft dabei Dispose auf, oder)... Und nun käme es zum Invoke... dann wäre ja mein Objekt disposed... sollte ich da ein try-catch über meine gestamte Update-Methode einbauen?
Greets
Mika
Hallo mika92,
es ist natürlich besser zu verhindern, dass eine ObjectDisposeException auftritt, als sie wegzufangen.
Dazu sagt man im FormClosing dem Thread Bescheid, dass er sich beenden soll und bricht das Schließen erstmal ab. Erst wenn der Thread (in der letzten Anweisung) dem Form sagt, dass er fertig ist, schließt man das Form endgültig.
herbivore
Aber woher weiß ich, was genau die letzte Zeile meines GUI-Threads ist?
Sry, die Frage kommt jetzt vielleicht ein bisschen blöd.
Das mit dem Schließen abbrechen sollte ich aus dem Gedächtnis heraus noch schaffen.
Aber in meinem FormClosing führe ich doch nur den einen Befehl aus... und es kann eben bei einem ganz blöden zufall sein, dass dann noch ein invoke folgt... und das müsste ich abfangen und habe keine plan wie... gg
Greets
Mika
Hallo mika92,
Aber woher weiß ich, was genau die letzte Zeile meines GUI-Threads ist?
die letzte Zeile des Worker-Threads. Zuerst muss der Worker beendet werden. Dann kann man das Fenster schließen und dann erst den GUI-Thread.
und es kann eben bei einem ganz blöden zufall sein, dass dann noch ein invoke folgt...
Nein, bei dem von mir beschrieben Vorgehen kann das nicht sein.
herbivore