C# Synchronisierung von Statusbalken

(Firma: keine) #2061052
Lesenswert?

Hallo,

habe ein kleines Problem bzgl. WinForms in C#. Ich möchte einen 
Statusbalken auf meiner MainForm über einen Event triggern. Dieser Event 
wird von einem anderem Thread aufgerufen. Ich behandle das 
cross-threading-Ereignis mittels "this.Invoke". Invoke ruft dann, 
mittels eines Delegaten, mein "ProgressBar.PerformStep()" aus.

So weit alles dufte. Nur wird eben das grafische Umsetzen des 
Prozessbalkens nicht sofort ausgeführt. Da die Applikation etwas 
schneller läuft, kommt der Balken nur bis ca 80% wenn die Anwendung 
schon fertig ist. Füge ich "wait states" ein, bzw. führe ich 
debug-Einzelschritte aus, dann geht's.

Gibt es eine Möglichkeit das zu synchronisieren? Also das das Programm 
erst weiter läuft, wenn der doofe Balken sich erneuert hat? Das Programm 
ist nicht Zeitkritisch, somit wäre es nicht tragisch zu warten.
(Firma: keine) #2061228
Lesenswert?

ok, danke erstmal. Also da ich ja synchron bleiben möchte, habe ich ja 
auch Invoke anstelle von BeginInvoke benutzt. Leider wird der Befehl 
zwar ausgeführt, bis es aber auf der GUI angekommen und gezeichnet ist, 
vergeht komischerweise sehr viel zeit...
Aus einem anderen Forum habe ich Folgendes:

"Yes, there can be an arbitrarily long delay. Invoke works by sending a 
Windows message to the target control, so it will only get processed 
when the target thread pumps messages. If the thread is already 
processing a message, and that processing takes time, then there may be 
an appreciable delay before the thread pumps its next message and 
thereby processes the Invoke."
Gast #2064980
Lesenswert?

Hi,

also an und für sich ist der Invoke-Aufruf synchron. Rein in den 
GUI-Thread, und der Event-Thread bleibt solange hängen, bis die 
Invocation fertig ist und zurückkehrt. Geht ja auch gar nicht anders, 
weil aus dem Invoke ein Returnwert rauspurzeln kann, der aus dem 
GUI-Thread stammt.

Das, was du beschreibst, deutet darauf hin, dass der Event-Thread nicht 
recycelt wird, sondern dass jeder Progress-Event auf einem neuen Thread 
kommt. Dann stauen sich die Threads in der Message-Queue der GUI. Du 
müsstest deinen Event-Werfer dazu bringen, single-threaded zu arbeiten.
(Firma: keine) #2065113
Lesenswert?

wo genau macht es sinn diesen befehl auszuführen? Mein momentaner 
ablauf:
thread triggered event auf form. der passende event handler auf der form 
sieht so aus:

1
      private void FlashProgressBar()
2
        {
3
            if (this.InvokeRequired)
4
            {
5
                this.EndInvoke(this.BeginInvoke(new MethodInvoker(delegate { progressBar2.PerformStep(); })));
6
            }        
7
        }
Gast #2065474
Lesenswert?

__tom schrieb:
> hinweise zu DoEvents():
> http://msdn.microsoft.com/en-us/library/system.win...

Hier vor allem den Caution-Absatz beachten:

Caution
Calling this method causes the current thread to be suspended while all 
waiting window messages are processed. If a message causes an event to 
be triggered, then other areas of your application code may execute. 
This can cause your application to exhibit unexpected behaviors that are 
difficult to debug.

Mit anderen Worten, das kann ordentlich ins Auge gehen. Das Problem ist, 
dass DoEvents alle wartenden Messages abarbeitet (auch die, die man 
nicht selbst erzeugt hat) und dass man keinen Einfluss darauf hat, 
welchen Rattenschwanz von Aktionen das hinter sich herzieht.

Peterle Anonym schrieb:
> und wie? haste ne idee?

Na ja, das kommt drauf an, wie das bisher programmiert ist. Ist es denn 
so, dass die Event-Quelle für jeden Event "new Thread" oder sowas macht 
und diesen dann den Event feuern lässt? Wenn ja, dann bau das mal aus 
und wirf den Event direkt aus dem Workerthread.
(Firma: keine) #2065513
Lesenswert?

besucher schrieb:
> Na ja, das kommt drauf an, wie das bisher programmiert ist. Ist es denn
> so, dass die Event-Quelle für jeden Event "new Thread" oder sowas macht
> und diesen dann den Event feuern lässt? Wenn ja, dann bau das mal aus
> und wirf den Event direkt aus dem Workerthread.

new thread? Nein, das ganze sieht so aus:

Klassen:
MainForm.cs->I/O.cs

I/O.cs:
ein thread der ständig ein reveive bit pollt. wurde was empfangen, wird 
ein event getriggert:
1
pThreadWrite = new Thread(new ThreadStart(ReadThread));
2
pThreadWrite.Start();
3
...
4

5
private void ReadThread()
6
{
7
while(1)
8
{
9
    if (ReceiveEvent)
10
    {       
11
    FlashProgressBar();
12
    }
13
}
14
}

Der handler auf der main form:
1
     private void FlashProgressBar()
2
        {
3
            if (this.InvokeRequired)
4
            {
5
                this.EndInvoke(this.BeginInvoke(new MethodInvoker(delegate { progressBar2.PerformStep(); })));
6
            }        
7
        }


Ich weiss nun, dass es eindeutig ein timing problem ist. habe ein leeres 
projekt erstellt und die progressbar getriggert mit einem event, das ca 
alle 300 ms auslöst. bei erreichen von 100 werten, war die progress bar 
selbst erst auf ca 80%. sie kam einfach nicht hinterher und ihre 
bearbeitung (window refresh) hing noch in irgendeiner queue. Ich möchte 
das aber unbedingt synchronisiert haben!!!
#2065560
Lesenswert?

Peterle Anonym schrieb:
> ein thread der ständig ein reveive bit pollt. wurde was empfangen, wird
> ein event getriggert:

Das ist mir auch noch aufgefallen: Was heißt "der ständig ein receive 
bit pollt"? Wird da auf ein Event gewartet oder ist das wirklich ein 
aktives Polling? Soll heißen, der Thread verbrät laufend CPU-Zeit damit, 
abzufragen ob ein Ereignis anliegt? Wenn letzteres der Fall ist, geht 
hier mit ziemlicher Sicherheit die von der GUI benötigte Rechenzeit 
flöten.

Gruß
Markus

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren