Erstellung eines Worker-Threads zur Grafikausgabe



  • Hallo zusammen,

    nun bin ich schon eine Weile am rumlesen, bekomme aber trotzdem kein funktionierendes Teil hin.

    Ich habe eine Grafik-Klasse (CViewGrafik), die über eine Methode (CViewGrafik::DrawGrafik())
    einige Messwert-Grafen ausgibt:

    CViewGrafik::DrawGrafik()	// Von CView abgeleitet
    {
    	DrwaLines();	// Dauert sehr lange
    }
    

    Da mein Programm auf diese Art die Grafik nicht fertigzeichnet und stattdessen
    mit dem Zeichnen ständig von Neuem beginnt ("Programm antwortet nicht"),
    muss ich das irgendwie in einen Thread auslagern, und zwar so, dass die
    Methode "DrawGrafik()" abschliesst und DrawLines im Hintergrund durch einen WorkerThread
    gezeichnet wird. Das heisst auch, dass "DrawGrafik" nicht auf den Thread warten darf.

    Ich brauche also auch keine Synchronisation. Was ganz einfaches also. (Buttons werde ich deakivieren...)
    Es wäre auch gut, wenn der Thread ein Member der Klasse "CViewGrafik" wäre!
    Er muss ebenauf diverse Klassen-Vars zugreifen.

    Vorgestellt habe ich mir etwas wie:

    CViewGrafik::DrawGrafik()
    {
    	HANDLE hGrafikThread;
    
    	hGrafikThread = CreateThread(0, 0, GrafikThread, 0, 0, 0);
    }
    

    Sich beenden und aufräumen muss der Thread dann selber.
    "GrafikThread" wäre dann der Ersatz für "DrawLines()"

    Leider bekomme ich das mit den gefundenen Tutorials nicht hin.
    Kann mir da bitte jemand helfen?
    Richtige Deklaration und Aufruf?

    Vielen Dank
    Helmut



  • Was genau meinst du mit "Grafik"? Sind das Fenster oder malst du irgendwas auf nen Device Context?



  • Mit MFC im speziellen habe ich zwar direkt noch nie was gemacht, aber alle GUI Libraries die ich so kenne machen GUI Kram ausschließlich im "Main Thread". Daher würde ich dringend davon abraten, in einem Worker Thread was zu zeichnen.

    Die Fehlermeldung "Programm antwortet nicht" kann auch einfach darauf hindeuten, dass du irgendwo eine Endlosschleife hast, oder auf ein Thread wartest, der sich nicht beendet.



  • @DocShoe Ja, ich male einfach was in einen DeviceContext



  • @Schlangenmensch
    Nein, ich habe keine Endlosschleife.
    Andere Messgrafen laufen ja perfect durch.
    Aber nun sind plötzlich Anforderungen, wo schon mal
    1.000.000 und mehr Daten zusammenkommen, für die auch noch diverse Berechnungen durchgeführt werden müssen, etc.



  • @elmut19
    Wie Schlangenmensch schon sagte vertragen sich nebenläufige Threads und Grafikausgabe häufig nicht besonders gut. Ein Ansatz könnte sein, im nebenläufigen Thread eine Bitmap zu erzeugen und auf der rumzumalen. Wenn die dann fertig ist muss der Zeichen-Thread dem Hauptthread signalisieren, dass er fertig ist und der Hauptthread kopiert den Bitmap Inhalt auf den finalen Device Context. Das erfordert zusätzlich Synchronisation zwischen den beiden Threads, damit der eine dem anderen nicht dazwischenfunkt.

    Dein hGrafikThread Handle solltest du dir als Member in der DrawGrafik Klasse ablegen, damit du den Thread später sauber beenden und das Handle wieder freigeben kannst.

    Zwei Stilfragen: Ungarische Notation ist out und eine Vermischung von Deutsch und Englisch in einem Wort lässt´s mir kalt den Rücken runterlaufen. Brrrrr.

    Edit:
    Sind sämtliche Messdaten zum Zeitpunkt des Zeichnens bekannt? Oder werden die nach und nach ergänzt? Worauf ich hinaus will: Wird DrawLines nur ein Mal aufgerufen oder immer wieder, wenn neue Messdaten eintreffen?



  • @DocShoe
    Das Programm ist schon alt und hat mehrere Stilfehler.
    Das ist erstmal belanglos.
    Bitmaps kommen mir sehr kompliziert vor.
    Die Grafik kann schliesslich auch gezoomt werden, ein Fadenkreuz anzeigen.
    Ich brauche somit auch immer diverse Parameter.
    Ich denke, das ich mit dem Deaktivieren der Bedien-Buttons auskommen kann.
    Zumindest vorerst.
    Hauptsache, ich kann mal damit experimentieren.



  • @elmut19
    Problem:
    Meine Grafikausgabe ist zu langsam, und wenn ich das in einen Thread verpacke stürzt mein Programm ab.

    Antwort:
    Du brauchst nen nebenläufigen Thread, der mit seinen eigenen GDI Objekten arbeitet und musst das mit dem Hauptthread synchronisieren

    Reaktion:
    Das ist mir zu kompliziert.

    Reaktion, Teil 2:
    WTF? Wasch mich, aber mach mich nicht nass?



  • @DocShoe
    Na ja, möglichst einfach eben.
    Wenn ich das brauche, muss es eben sein.
    Ich habe das zumindest noch nicht gemacht.

    Mein Programm stürzt auch nicht ab, da ich mit dem Thread noch gar nicht so weit bin.
    Ich muss den erst mal bauen.
    Und das scheitert schon an der Deklaration.

    Zur Bitmap:
    ich kann den Bildschirm nicht ein oder zwei Minuten leer lassen, bis die Bitmap gezeichnet ist.
    Wenn, dann ist es mir schon viel lieber, man sieht, wie die Grafik aufgebaut wird.
    Dann weiss man auch, dass etwas gemacht wird.

    Und wie geht das?
    Wie deklariere ich alles?



  • @elmut19
    Das ist eher viel zu erklären, und ich kenne mich mit der MFC nicht mehr aus. Du kannst aber die WINAPI benutzen und dir die Funktionen CreateCompatibleDC , CreateCompatibleBitmap, BitBlt, CreateCriticalSection, EnterCriticalSection , LeaveCriticalSection und WaitForSingleObject angucken. Und natürlich SelectObject, DeleteObject und CloseHandle. Und vermutlich noch ein paar andere.

    Edit:
    Hier ist in der Paint Methode schon mal erklärt, wie man eine Offscreen DeviceContext und -Bitmap erstellt.



  • @elmut19 sagte in Erstellung eines Worker-Threads zur Grafikausgabe:

    Na ja, möglichst einfach eben.

    steht im Widerspruch zu

    @elmut19 sagte in Erstellung eines Worker-Threads zur Grafikausgabe:

    Wenn, dann ist es mir schon viel lieber, man sieht, wie die Grafik aufgebaut wird.
    Dann weiss man auch, dass etwas gemacht wird.



  • @manni66
    Nun ja, die Anforderung wäre dann eben "ohne Bitmap" und dann eben auch alles, was man dazu braucht.



  • @elmut19 sagte in Erstellung eines Worker-Threads zur Grafikausgabe:

    Da mein Programm auf diese Art die Grafik nicht fertigzeichnet und stattdessen
    mit dem Zeichnen ständig von Neuem beginnt ("Programm antwortet nicht"),

    "Programm antwortet nicht" heisst nicht, dass "ständig von Neuem begonnen" wird. Du solltest erst mal herausfinden, was eigentlich passiert und warum es so langsam ist.



  • @manni66
    Ich sehe ja, dass im Fenster-Kopf der Anwendung diese Meldung steht "Programm antwortet nicht".
    Ich sehe dann auch, dass der Bildschirm neu aufgebaut wird und die Grafik wieder von vorne gezeichnet wird.
    Ich habe mir den Quellcode auch schon sehr oft angesehen..
    Leider habe ich noch keine Möglichkeit gefunden, den schnelle zu machen.



  • @DocShoe sagte in Erstellung eines Worker-Threads zur Grafikausgabe:

    Edit:
    Sind sämtliche Messdaten zum Zeitpunkt des Zeichnens bekannt? Oder werden die nach und nach ergänzt? Worauf ich hinaus will: Wird DrawLines nur ein Mal aufgerufen oder immer wieder, wenn neue Messdaten eintreffen?

    Ich glaube, die Frage ist untergekommen, wäre aber interessant zu wissen.

    Eventuell lassen sich auch Berechnungen in einen Thread auslagern, so dass der Hauptthread dann nur grade neu berechnete Endwerte anzeigen muss. Aber auch hier ist eine entsprechende Synchronisation nötig.

    Aber wo genau der Flaschenhals ist, ist mit den Informationen schwer zu erraten.

    Ich würde das mit der Bitmap versuchen. Du kannst ja messen, wie lange das dauert. Und dann hast du das Teilproblem zumindest schon so weit separiert, dass man da vlt einfacher andere Performance Optimierungen vornehmen kann.



  • @elmut19 sagte in Erstellung eines Worker-Threads zur Grafikausgabe:

    Ich sehe dann auch, dass der Bildschirm neu aufgebaut wird und die Grafik wieder von vorne gezeichnet wird.

    Und warum startet es wieder von vorne?
    Wie kann das überhaupt sein, wenn der GUI Thread doch blockiert ist?



  • @elmut19 Von Threads würde ich erst einmal Abstand nehmen. Sie alleine sind nicht die Lösung für das ursprüngliche Problem.
    Mit Double-Buffering, also das Zeichnen in eine Bitmap, würden sich sehr viele, wenn nicht alle Probleme auf einen Schlag lösen lassen.
    Der Grundgedanke dahinter ist eigentlich nur, dass Zeichenoperationen nur dann und direkt erfolgen, wenn sie nötig sind und beim Zeichnen in den DC lediglich die Bitmap in den DC geblittet wird.
    Wenn du das allerdings das erste Mal machen möchtest, würde ich dringend ein Testprojekt dafür empfehlen...
    Es wäre dann auch einfacher, bei konkreten Problemen zu helfen.



  • @manni66
    Leider weiss ich den Grund für den Wiederaufbauf der Grafik nicht.
    Ich denke, dass das Betriebssystem zu lange keine Antwort bekommt.
    Auch habe ich keinen eigenen GrafikThread. Es ist das Hauptprogramm, das da zeichnet.
    Ich habe auch schon probiert durch abfragen der Message Queue das zu beheben. Hat nix gebracht,



  • @elmut19
    Kommt drauf an, wo deine Zeichenoperation angeschubst wird. Es gibt mehrere Gründe, warum dein Fenster ein WM_PAINT bekommt. Und wieso kann man das nicht rausfinden? Einen Brechpunkt auf DrawLines setzen und sich den Callstack angucken.



  • @elmut19 sagte in Erstellung eines Worker-Threads zur Grafikausgabe:

    Auch habe ich keinen eigenen GrafikThread. Es ist das Hauptprogramm, das da zeichnet.

    Das ist klar. Wenn aber

    DrwaLines();	// Dauert sehr lange
    

    nicht bendet wird, kann es nicht neu starten.

    @elmut19 sagte in Erstellung eines Worker-Threads zur Grafikausgabe:

    Leider weiss ich den Grund für den Wiederaufbauf der Grafik nicht.

    Dann finde es heraus. Ein Thread ist nicht zum totschlagen von Problemen, die man nicht versteht, geeignet.


Log in to reply