Verzögerte Nachrichten bei Multithreading mit Multicore-Prozessoren?



  • Mein CAD-Prozess (Hauptthread) startet für jedes Zeichenfenster, in das gerade Elemente gezeichnet werden müssen, einen eigenen Thread (_beginthread). Nach vollendeter Zeichenaktion wird er wieder terminiert. Die Synchronisation erfolgt über critical sections.

    Nun soll der Zeichnungsaufbau bei Änderung des Zoomfaktors oder der Zeichenmitte (Scrolling) aber nicht zu Ende geführt, sondern vorzeitig unterbrochen und mit den neuen Einstellungen neu gezeichnet werden. Diese Änderung erfolgt z.B. über einen Scrollschieber via WM_VSCROLL.

    Wenn das Programm auf einem Prozessor mit mehreren Kernen läuft, kommt diese Nachricht WM_VSCROLL aber erst an, wenn sich der Zeichnungsthread terminiert hat. Wenn der Prozess durch Maskierung auf nur einen Kern beschränkt wird oder das Programm auf einem älteren Ein-Kerner oder auf XP oder älter läuft, funktioniert es: Der Hauptthread erhält in der Fensterprozedur das WM_VSCROLL, die Anwendung kann reagieren und der Zeichnungsthread wird vorzeitig stoppen und neu zeichnen.

    Ist dies ein Problem des Schedulers ab Windows Vista bei Mehrkernern? Wo wird die Nachricht aufgehalten? Offenbar schon vor der Message-Queue der Anwendung?!


  • Mod

    Sieht mir eher nach blockierten Threads aus.
    Sendet denn der Zeichnen-Thread Nachrichten an einen anderen Thread der wartet?

    Welche Threads haben Nachrichtenschleifen?
    Wie gehst Du bitte mit einem WM_PAINT um? Du musst doch in diesem Moment auch irgendwie zurückkommen sonst ist die Nachrichtenschleife doch blockiert. Selbst wenn das Fenster noch nicht neu gezeichnet ist.
    Was machst Du mit dem Paint DC?
    Welchen DC verwendest Du eigentlich beim schreiben?

    Die Hintergründe können vielfältig sein... DCs sind nicht für Multithreading gebaut... alleine hier kann dein erzwungenes Singlethreading schon verrückte Effekte herbeiführen. Durch Dein Verfahren werden alle Aktionen brav hintereinander ausgeführt. Probleme scheint es eben beim zeitgleichen Zugriff zu geben. Das hat nichts mit dem Scheduler zu tun sondern vermutlich eben mit falschen Umgang von Objekten, die nicht für Multithreading gebaut sind.
    Just my 2 Cents.



  • Wie kannst Du denn in einem anderen Thread zeichnen? MemDC? In das Fenster geht das ja nicht...



  • Ich gebe zu, dass es sich um ein sehr komplexes Thema handelt, das zunächst vielfältige Fehlerquellen vermuten lässt. Das C++-Programm läuft allerdings in dieser Form schon in mehreren Versionen seit über 10 Jahren fehlerfrei. Thread-Blockaden wären sofort festzustellen.

    Interessant ist dein Einwand bezüglich der DCs. Ist die GDI grundsätzlich nicht multithreadfähig? Die Übersetzungen, Bibliotheken usw. sind natürlich entsprechend eingestellt.
    Es werden GDI- und GDIplus-Routinen verwendet, aber nicht threadübergreifend. Auch die Beschaffung und Freigabe von DC bzw. Graphics finden im selben Zeichnungsthread statt. Es können mehrere Threads jeweils ein Zeichenfenster gleichzeitig zeichnen. Das Phänomen tritt aber auch bei Haupt- und nur einem Zeichenthread auf.

    Ausschließlich der Hauptthread empfängt Nachrichten. Ein WM_PAINT übergibt die Info an den Zeichnungsthread, dass ein Zeichnungsvorgang vorzeitig abgebrochen und neu begonnen werden soll. Dieser Kommunikationsvorgang ist kompliziert, aber keinesfalls die Ursache. Das WM_PAINT, eigentlich z.B. ein WM_VSCROLL, das seinerseits durch InvalidateRect und UpdateWindow das WM_PAINT verursacht (alles Hauptthread), kommt, während der Zeichnungsthread läuft, verspätet an! Daran kann ich ja nichts direkt ändern, weil die Control-Nachricht WM_VSCROLL bereits verspätet vom System kommt. Alles andere danach bis zum WM_PAINT und der Reaktion im Zeichnungsthread läuft blitzschnell.

    Entscheidend bleibt, dass das Laufzeitverfahren bei Benutzung von mehreren Prozessorkernen ein anderes als bei einem Einkerner ist. Fehler entstehen dadurch ja nicht, aber im ersten Fall fehlt der Feinschliff in der Performance.



  • Hallo Jochen,

    wieso sollte man nicht in ein Fenster, das vom Hauptthread erstellt wurde, mit einem Thread zeichnen können? Der DC muss natürlich im Zeichnungsthread beschafft werden. Ich übergebe nicht den WM_PAINT-HDC in den Zeichnungsthread! Der ist mit EndPaint wieder weg.


  • Mod

    Genau. Das geht. Die Frage ist jetzt:
    - Wartest Du im Mainthread auf irgendwas aus dem Zeichnungsthread?
    - Wie kommunizierst Du zwischen Zeichnungsthread und Mainthread?

    Führe doch das Programm in diese Art "Blockade" und Klicke im Debugger auf "Break All". Dann schau wo welcher Thread was macht...


Anmelden zum Antworten