Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
WindowsForm friert ein, Threadübergreifender Zugriff auf Label
dodoflash
myCSharp.de - Member



Dabei seit:
Beiträge: 3

Themenstarter:

WindowsForm friert ein, Threadübergreifender Zugriff auf Label

beantworten | zitieren | melden

Hi,
Hoffe ich bin hier richtig.
Hab ein Problem mit einem Threadübergreifenden Zugriffe auf die Eigenschaft label.visible.

Ich verwende Aforge.net für die Wiedergabe einer mpg.datei. Über den newFrame-Event wird bei jedem neuen Bild das der videosourceplayer erhällt eine Algorithmus zur Bildbearbeitung ausgefürt.

Dieser Liefert einen Wert der je nach Höhe ein Label visible= true bzw. false setzt.

Da der direkte Zugriffe auf die Steuerelemente zu einer Exception führt. Habe ich mir ein paar Codeschnippseln zusammengesucht und das über delegaten geregelt.

Hier der Code:

New-Frame-Event von dem aus die Änderung des Steuerelements aufgerufen wird



private void videoSourcePlayer1_NewFrame(object sender, ref Bitmap image)
{
            ...........Algorithmus der count festlegt.......  

              if ((count ≥ DetectionValue) && (TrainDetected == false))
               {
                   TrainDetected = true;
                   Zugdetektion(true);
               }
               if ((count < DetectionValue) && (TrainDetected == true))
               {
                   TrainDetected = false;
                   Zugdetektion(false);
               }
               
               // Edit: Ohne diesen zweiten Aufruf schein alles zu funktionieren 
               WriteTextBox("Frames: " + Count);
}


Änderung des Steuerelements:


delegate void ZugdetektionDelegate(bool detected);
       private void Zugdetektion(bool detected)
       {
           if (label5.InvokeRequired)
           {
               label5.Invoke(new ZugdetektionDelegate(this.Zugdetektion), new object[] { detected });
           }
           else
           {
               if (detected)
                   label5.Visible = true;
               else
                   label5.Visible = false;
           }
       }


Zweite Änderung eines Steuerelements:


delegate void WriteTextBoxDelegate(string text);
       private void WriteTextBox(string text)
       {
           if (label3.InvokeRequired)
           {
               label3.Invoke(new WriteTextBoxDelegate(this.WriteTextBox), new object[] { text });
           }
           else
           {
               label3.Text = text;
           }
       }


Dabei kommt es zu folgendem Fehler:

Das Video und die gesamte Form friert ein und beim Versuch mit Pause im Debugger in den derzeitigen ausgeführten Code zu gelangen wird immer Application.Run(new Form1());
angezeigt. Breakpoints im Programmcode haben ebenfalls zu keinem Aufruf geführt sobald die Form eingefrohren ist.
Der Fehler passert immer exact nach der selben Anzahl von erhaltenen Frames. Geht man den Code ab dieser Zahl händisch mit Breakpoints durch kommt es zu keiner Fehlermeldeung und der Code wird normal ausgeführt. Sobald man das Programm dann allerdings wieder laufen lässt friert wieder alles ein.

Edit: Also scheint so als ob die zwei Aufrufe auf die labels sich gegenseitig irgendwie stören und den freeze auslösen. Wenn nur eins von beiden verwendet wird funktionierts einwandfrei.

Wäre nett wenn wer einen Rat hätte was hier falsch rennt.


Danke und lg
dodoflash
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von dodoflash am .
private Nachricht | Beiträge des Benutzers
rollerfreak2
myCSharp.de - Member

Avatar #avatar-3271.jpg


Dabei seit:
Beiträge: 928

beantworten | zitieren | melden

Hallo dodoflash,

und willkommen im Forum.

Ich vermute mal du knallst die Windows MessageQueue voll. Das heißt du Invokes zu viel, und der GUI Thread ist ständig damit beschäftigt die GUI Zugriffe auszuführen. Versuch mal mit BeginInvoke statt Invoke zu arbeiten, bzw. solltest du dir überlegen, ob es Sinnvoll ist die UI so oft upzudaten. Das kann das menschliche Auge gar nicht wahrnehmen :D Ich denke all 10 Frames reicht auch zu.
Again what learned...
private Nachricht | Beiträge des Benutzers
dodoflash
myCSharp.de - Member



Dabei seit:
Beiträge: 3

Themenstarter:

beantworten | zitieren | melden

Okay werd das mal versuchen.

Zu oft wird eh nicht upgedated, immer nur wenn sich der Status ändert wird zw. visible true und false und das ist eigentlich nur 2 bis 3 mal wenn alles funktioniert für ein file (ca. 1min) ansonst bleibt das label gleich.

Das zweite label gibt nur die anzahl der Frames an, und auch das ist eigentlich nicht wirklich flott durch den algorithmus davor gibts nur ca alle 700ms eine Änderung und man sieht das schon mit freiem Auge.

Aber ich werd das mit dem BeginInvoke mal versuchen. Thx
private Nachricht | Beiträge des Benutzers
rollerfreak2
myCSharp.de - Member

Avatar #avatar-3271.jpg


Dabei seit:
Beiträge: 928

beantworten | zitieren | melden

Ob das nur 2-3 mal geändert wird ist die eine Frage, jedoch so wie ich das sehe, machst du trotzdem nach jedem Frame ein GUI zugriff via Invoke. Was dann dort drin passiert, bzw. ob dort in dem delegaten überhaupt was passiert ist eine andere Frage, aber die MessageQueue müllst du dennoch voll!
Again what learned...
private Nachricht | Beiträge des Benutzers
dodoflash
myCSharp.de - Member



Dabei seit:
Beiträge: 3

Themenstarter:

beantworten | zitieren | melden

Okay also mit BeginInvoke funktioniert es einwandfrei thx.
Werd mir aber auch noch den Link anschauen den ich geschickt bekommen habe.

[FAQ] Warum blockiert mein GUI?

Danke für die schnellen Antworten.
private Nachricht | Beiträge des Benutzers
ujr
myCSharp.de - Experte



Dabei seit:
Beiträge: 1770

beantworten | zitieren | melden

Hallo,

ich würde die Ursache eher woanders suchen. Hast Du weitere Threads und/oder Timer, die auf die GUI zugreifen?

Die Aktualisierung von zwei Labels (2x Invoke nacheinander) kann nicht zu einem Deadlock führen - es würde höchstens etwas langsamer und ruckelig werden. Allerdings verdoppelt sich natürlich die Wahrscheinlichkeit für das Auftreten des Problems an anderer Stelle.

BeginInvoke kann natürlich das Problem erstmal entschärfen, da es nicht blockiert, aber die Ursache sollte man trotzdem verstehen und nicht einfach solang herumbasteln bis es geht (sinngemäßes Zitat von herbivore).
Übrigens sollte man ja meinen, dass die "Message queue" bei BeginInvoke mehr beansprucht wird als bei Invoke, denn Invoke kehrt erst dann zurück, wenn ein Eintrag bearbeitet wurde.

Noch ein paar Bemerkungen:
- [Tipp] Anfängerfehler == true / == false
- Die Abfrage auf "InvokeRequired" ist unnötig, da der Aufruf sicher aus einem Nicht-GUI-Thread erfolgt
- und natürlich ist es nicht optimal, für jede einzelne Update-Aktion ein eigenes Invoke zu benutzen (Zugdetektion und WriteTextBox)
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von ujr am .
private Nachricht | Beiträge des Benutzers
rollerfreak2
myCSharp.de - Member

Avatar #avatar-3271.jpg


Dabei seit:
Beiträge: 928

beantworten | zitieren | melden

Zitat
Über den newFrame-Event wird bei jedem neuen Bild das der videosourceplayer erhällt eine Algorithmus zur Bildbearbeitung ausgefürt.
Zitat
Die Aktualisierung von zwei Labels (2x Invoke nacheinander) kann nicht zu einem Deadlock führen

Ich denke wenn man 2 Labels 100 mal in der Sekunde updated dann kann das schon zu einem deadlock führen. Weil wie ich schon erwähnt habe Invoked er die sachen immer, und checked nicht mit einem flag ob das Label sowieso schon visible ist. Das Visible Flag selber darf er ja nicht abfragen da auch lesende Zugriffe auf GUI Elemente außerhalb des GUI Threads vermieden werden sollten.

Dennoch gebe ich ujr recht, das es eventuell noch eine andere Ursache für das Verhalten geben wird, als nur die beiden Label Invokations. Bezüglich der vielen verschiedenen Delegaten, schau dir auch mal Action delegate (.Net 4.0) bzw. das Func<T, TResult> (.Net 4.0) an.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von rollerfreak2 am .
Again what learned...
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 52329
Herkunft: Berlin

beantworten | zitieren | melden

Hallo rollerfreak2,

Control.Invoke arbeitet in Gegensatz zu Control.BeginInvoke synchron. Daher ist es bei Control.Invoke im Gegensatz zu Control.BeginInvoke unmöglich, dass man "die Windows MessageQueue voll knallt". Durch Control.Invoke steht (pro Thread) zu jedem Zeitpunkt maximal ein Eintrag in der MessageQueue. Nur mit Control.BeginInvoke kann man die "die Windows MessageQueue voll knallen".

Trotzdem kann man das GUI mit unnötig häufigem Aufrufen sowohl von Control.BeginInvoke als auch von Control.Invoke de facto zum Erliegen bringen, weshalb man die Zahl der Aufrufe (pro Sekunde) gering halten sollte.

Aber das und alles andere hier im Thread steht auch schon in dem von dodoflash geposteten Link und seinem "Bruder" [FAQ] Controls von Thread aktualisieren lassen (Control.Invoke/Dispatcher.Invoke).

herbivore
private Nachricht | Beiträge des Benutzers