Thread Sheduling Änderungen von Windows XP nach Windows 7



  • Destiniy schrieb:

    es scheint so als geht WAIT_IO_COMPLETION vor den anderen Events

    also das event auf das ich warte wird gesetzt, und bevor es ausgelöst wird kommen so 30 WAIT_IO_COMPLETION events vorher

    Ja, ist ja auch ganz normal - wenn APCs anstehen und man "alertable" wartet, dann werden halt erstmal die APCs abgearbeitet.

    Die Frage ist: warum sind 30 APCs vor der "erwünschten" Nachricht ein Problem? Dauert das Abarbeiten der APCs so lange?
    Wenn ja dann hast du da ein grundlegendes Problem, nämlich dass weniger wichtige APCs abgesetzt werden, die dann wichtigere Ereignisse verzögern.

    U.u. könnte man sich mit einem Hack behelfen: wenn du die Abarbeitung von bestimmten Events bevorzugt machen willst, dann prüf einfach vor dem "alertable" WaitForMultipleObjectsEx mit einem "nicht alertable" WaitForMultipleObjectsEx nur diese bevorzugten Events.
    Also z.B. so:

    // Erst die wichtigen Events mit timeout = 0 und alertable = false prüfen
    // (Die wichtigen Events müssen dabei dir ersten in "allEvents" sein. Dadurch brauchen wir nur ein Array, und vor allem bedeutet dann der Returnwert immer das selbe,
    //  wir können also das selbe switch() verwenden egal welcher WaitForMultipleObjectsEx() das Ergebnis geliefert hat)
    DWORD rc = WaitForMultipleObjectsEx(importantEventsCount, allEvents, false, 0, false);
    // Wenn nichts wichtiges anliegt normal warten
    if (rc == WAIT_TIMEOUT)
        rc = WaitForMultipleObjectsEx(allEventsCount, allEvents, false, timeout, true);
    switch (rc)
    {
        ...
    

    p.s.: Falls das zu unerwünschten Nebeneffekten führt, z.B. andere Dinge zu arg verzögert, dann hilft vielleicht wenn das "importantEvents" WaitForMultipleObjectsEx nur bei jedem 2. Durchlauf gemacht wird. Wenn permanent APCs und "wichtige" Events anstehen würden die APCs dann nicht ausgehungert, sondern immer ein APC, ein Event, ein APC, ein Event etc. abgearbeitet.



  • Jochen Kalmbach schrieb:

    dot schrieb:

    Was für einen Vorteil hätte er von timeBeginPeriod(1), wenn er QueryPerformanceCounter() verwendet

    Das eine hat mit dem anderen nichts zu tun...

    Eben, da ich die API aber nur im Zusammenhang mit der Genauigkeit von gewissen Timern kenne und nur weiß, dass sie im Prinzip den Heartbeat des Schedulers erhöht, würde mich interessieren, was genau man in dem Fall hier davon hat bzw. haben könnte, rein aus Interesse.



  • Wenn man den Heartbeat des Schedulers erhöht, so erhöht sich automatisch auch die Reaktionszeit von Waitable-Objects... als ein WaitFor...Object wird somit "schneller"...
    Das ganze hängt natürlich auch noch von den anzahl der ReadyToRun Threads ab... also wenn _keine_ ReadyToRun sind, dann merkt man keinen Unterschied. Aber wenn es mehrere sind, dann kann es schon was ausmachen, da jeder Thread ja öfter unterbrochen wird.... aber es hat, wie Du ja auch sagtest, Nachteile, wenn sehr viele Threads laufen. Wenn man aber gescheit programmiert hat man mehr Vorteile als Nachteile; zumindest aus meiner Erfahrung... und ich mache schon lange unter Windows mit Echtzeitsteuerung rum... aber hier meistens mit Fibers, da hier das (User-Mode) Scheduling noch schneller ist 😉



  • Jochen Kalmbach schrieb:

    also wenn _keine_ ReadyToRun sind, dann merkt man keinen Unterschied.

    Hm.
    Müsste das nicht genauer heissen "wenn keine ReadyToRun Threads mit gleicher Priorität da sind"?
    Threads mit niedrigerer Priorität sollten - wenn ich das Windows' Scheduling richtig verstehe - sofort unterbrochen werden. Und Threads mit höherer laufen so oder so weiter.

    Sonst würden einem vielbeschäftigte Background Threads ja die ganze Performance weglutschen. Das wäre Übel.



  • Ja, mir "gleicher und höherer Prio".

    Wobei man sagen muss, dass die meisten Synchronisations-Objekte von *User-Mode* Threads signalisiert werden. Somit ann man nicht sagen, dass nieder priore Threads sofort unterbroichen werden, wenn das Ereignis eintritt. Weil das ereignis ja vielleicht schon viel früher eingetreten ist, aber der nieder priore Thread erst später drankommt um einen möglicherweise höher prioren thread zu signalisieren.... aber jetzt wird es mehr theoretisch und dann spielt natürlich auch noch das dynamische erhöhen der Prio für solche Dinge eine Rolle. Das geht ja aber nur bis prio 15... ab prio 16 gibt es keine dynamische Erhöhung um solche Fälle besser abhandeln zu können...

    Meine Threads laufen alle mit Prio 32 😉 und dann via Fibers gescheduled... dann muss man sich auch keine Sorgen um Synchronisation machen 😉



  • Entschuldigung, dass ich hier so reinplatze... ich versuche mich gerade in das Threading reinzuwursteln und lese hier von Jochens Ansatz...
    Verstehe ich das richtig, dass du mit den Fibers sozusagen Threadpools umsetzt, wobei in jedem Pool kooperatives scheduling betrieben wird? Irgendwie verstehe ich das gerade nur so diffus, weil ich mir nicht genau erklären kann, was nun der Vorteil oder besser Unterschied gegenüber der "sequentiellen" Abarbeitung von Tasks in solch einem Thread ist. Schließlich muss ein Fiber ja explizit ein anderes Fiber aktivieren, wenn der Wechsel stattfinden soll, zumindest wenn ich die Doku richtig lese. Das heißt, ich meine zu verstehen, dass Fibers sich nicht "schlafen legen" können, während sie auf ein Event warten und dann automatisch wieder geweckt werden, sollte das Event eintreten (sie sind ja nicht mehr "aktuell", sobald auf ein anderes Fiber geswitcht wird).
    Hast du eventuell etwas Zeit, um das System etwas genauer zu erläutern? Würde mich sehr freuen mal von solch praktikablen Ansätzen zu lesen.

    Viele Grüße,
    Deci



  • Das System ist ein komplettes "Tasking-System" welches auch eigene Methode für alle möglichen Dinge hat:
    - Sleep
    - Semaphore
    - MsgQueues
    - usw.
    Eben alles, was man so von einen Task erwartet.

    Der größter Vorteil ist, dass man sich *nicht* um das synchronieren von Threads kümmern muss (wenn man nur einen User-Mode-Thread hat). Damit betreiben wir Anlagen mit ca. 4000 I/Os und 20 seriellen Schnittstellen in Echtzeit.
    Man muss nur einige Dinge beachte (keine Zugriffe auf Dateisystem usw.) um hier relativ sicher zu sein. Das System erlaubt auch das zeitweise "ausbrechen" aus dem Fiber-Verbund und dann ein ausführen als "normaler" Thread, welches dann wieder alles erlaubt.



  • So ich habe jetzt nochmal neue Informationen.

    Wenn ich das Programm auf einen Core force funktioniert es schnell genug.

    Jetzt verstehe ich das nicht. Ich habe n Threads die ich auf m Processor Cores verteile. Wenn m>1 ist läuft das Programm zu langsam. Wonach sollte man schauen?

    MfG



  • @jochen:

    gibts zu dem fiber - thema noch mehr informationen als die eher allgemein gehaltenen in der msdn? hört sich sehr intressant an!

    was mich da auch intressieren würde ist (bitte korrigieren falls ichs falsch verstehe) folgendes:
    die synchronisation zwischen den threads wird ja dadurch unnötig da man mit den fibers im selben prozessraum arbeitet. wenn jetzt mehrere io - schnittstellen daten liefern müssen die ja auch irgendwo hin... und spätestens beim zusammenführen der daten muss doch dann auch wieder irgendwie synchronisiert werden? verlagert sich das problem dadurch nicht nur?

    sorry fürs offtopic werden.



  • Ja, es gibt auch Methoden mit denen man asynchorn Messages oder Semaphore signalisieren kann. Dadurch kommt man auch von "außen" in das System rein...
    Das ganze wurde aber um das Fiber-Konzept drum-rum programmiert und ist nicht ganz trivial...
    WIr sollten entweder in "RUDP" oder "Projekte" weiterdiskutieren..



  • Hallo Leute,

    dürfte ich euch bitten zum Problem zurückzukehren:

    Wenn ich das Programm auf einen Core force funktioniert es schnell genug.

    Jetzt verstehe ich das nicht. Ich habe n Threads die ich auf m Processor Cores verteile. Wenn m>1 ist läuft das Programm zu langsam. Wonach sollte man schauen?

    MfG



  • Nun, damit ist es ziemlich eindeutig, dass der Synchronisationsoverhead in deinem Programm größer ist als der Nutzen durch die Parallelisierung. Vermutlich ließ der Windows XP Scheduler das Ding einfach sowieso großteils auf einem Core laufen, sodass es dort nicht auffiel. Was du machen kannst: Reduzier den Sync Overhead. Möglicherweise ist das Problem einfach nicht parallelisierbar? Dann verwend weniger Threads.


Anmelden zum Antworten