Wenn der Scheduler aber in einer ganz normalen Zeitscheibe läuft, spielt das keine Rolle - das Lock ist zu diesem Zeitpunkt immer frei.
Das trifft nur für die aktuelle CPU zu aber nicht für die anderen. Ob die anderen CPUs gerade einen Kontext-Switch durchführen (und deswegen die jeweils eigene Liste bearbeiten) oder nicht ist purer Zufall, egal ob der Haupt-Scheduler als Teil des Kernels läuft oder als User-Mode-Prozess.
Hmm, das ist ein Argument: die Zeitschreiben müssen ja nicht auf allen CPUs synchronisiert ablaufen. Das macht's schwieriger.
Ich denke die Kunst besteht darin einen kleinen lokalen Scheduler zu haben den jede CPU für sich aufruft um den nächsten Thread zu bekommen und ein paar Statistiken zu updaten
Das war der von mir geschilderte zweite Codepfad (der mit dem Injizieren). Den kann man natürlich auch noch etwas eleganter machen und ausschmücken. Da kriegst du auch meine volle Zustimmung.
und dazu einen großen globalen Schduler zu haben der nur dann aufgerufen wird wenn sich der Status-Quo ändert (z.B. wenn beim Aktualisieren der Statistik durch den kleinen Scheduler ein Ungleichgewicht eine gewisse Schwelle übersteigt oder Threads dazu kommen bzw. verschwinden/blockieren).
Ja, allerdings sehe ich nicht so das große Problem (wenn der große Scheduler gut skaliert!), wenn er gelegentlich zwangsverordnet wird, sich um alles kümmert, und dann erstmal zukünftig der kleine Scheduler einfach abarbeitet, was der große Chef erzählte.
Das ist zwar eine gute Idee aber wie viele Threads trifft das? Ich denke es gibt nur ganz wenige Situationen wo man einen kontinuierlichen Fluss an Arbeit hat (mit relativ konstanten Arbeit-pro-Zeit-Wert) wo immer mal wieder etwas zu tun ist, klassisches Beispiel wäre der Decoder-Thread in einem Media-Player.
Der läuft eh mit einer höheren Priorität, schließlich ist Multimedia eine Echtzeitanwendung und die kannst du, wenn auch nicht garantieren, dadurch recht zuverlässig bereitstellen. Außerdem blockiert er ständig, wenn er nichts mehr zu tun haben möchte und lässt sich per Signal wieder aufwecken.
Die überwiegende Mehrheit aller Threads arbeitet so lange bis die Arbeit zu Ende ist oder eine blockierende Aktion ausgeführt wird, ich denke das sind die 2 Fälle die ein Scheduler möglichst gut abdecken muss.
Andersrum: Die Mehrheit aller Threads arbeitet ihre Zeitscheibe ab oder blockiert vorher. Andere Fälle (endet vorher) sind die absolute Ausnahme. Das meintest du doch, oder?
Threads, die ihre Zeitscheiben regelmäßig aufbrauchen, behandelst du normal; Threads, die das nicht tun, bevorzugst du etwas. Vielleicht eine Prioritätsstufe. Den Rest deiner Zeitscheibe gibst du dann einfach nicht-interaktiven Prozessen, die können damit sicherlich auch was anfangen. Oder (im Gegensatz zu oben) du löst sich komplett von dem Problem der Zeitscheiben. Das führt zu einem sehr komplexen Scheduler (und erfordert einen interruptfähigen Timer je CPU, und die Möglichkeit, Interrupts auf eine bestimmte CPU zu routen), wäre aber mal ein interessantes Konzept.
Das Problem ist nur das dieser Gesamtüberblick um so teurer wird je größer das Gesamtsystem ist, also der Aufwand wächst mit der Anzahl der CPUs und mit der Anzahl der runnable Threads.
Das ist das schöne, wenn du für die Zukunft planst: Du kennst den Gesamtzustand schon, bevor er überhaupt existiert. Jedenfalls, solange dein Plan stimmt; aber bei einem Scheduler spekulierst du so viel, dass eine Minderheit an Fehlspekulationen nicht weiter stören sollte.
Wenn du viele CPUs hast, kannst du auch potentiell mehr CPU-Zeit für den Scheduler ausgeben; gegenüber der Anzahl der vorhandenen Threads solltest du aber möglichst ein O(1) produzieren.
"Ein Kompromiss ist die Kunst einen Kuchen so zu schneiden das jeder denkt er hätte das größte Stück!"
Erzähle das bloß nicht den Prozessen, die du auf deinem System hast (oder entziehe ihnen vorher jede Möglichkeit der Zeitbestimmung
).
Es dürfte aber auch einige Threads geben die für ein oder zwei Zeitscheiben gut Arbeit haben und dann wieder länger blockieren bevor wieder ein kleines Stück Arbeit zu erledigen ist (misst, mir fällt da jetzt gar kein Beispiel ein).
Das ist irrelevant; wenn sie blockieren, fallen sie aus der Betrachtung raus. Es gibt aber nur wenige Threads, die ihre Zeitscheiben immer voll ausnutzen und dann umschalten auf nie ausnutzen.
Auch das Aufwachen und wieder Einschlafen von Threads ist ein wichtiges Ereignis das den großen Scheduler erforderlich machen kann (aber sicher nicht immer muss).
Ja. Wenn die Queue für die CPU lang genug ist, kann sie ja erstmal damit weitermachen, was sie hat.
So lange die fetten Jobs alle mit niedrigerer Priorität laufen sollte der Tastendruck durch kommen, theoretisch zumindest.
Du weißt aber schon, dass niedrige Priorität erstmal nichts mit den I/O-Prozessen zu tun hat, oder? Wenn du auf einem 2.6.26er Kernel ein paar hundert Megabyte mit USB 1.1 wegschreibst, dann steht dein System auch, weil der Kernel gerne für Datensicherheit ist und die Daten committen möchte. Konkret rechnet er nicht damit, dass ein I/O-Gerät für so große Datenmengen so unglaublich langsam sein kann und alle Systemprozesse leiden. (Der Fehler, der das offensichtlich gemacht hat oder noch macht, ist, dass die Speicherverwaltung nahezu blockiert, weil sie den Speicher für das I/O braucht.)
Das sind dann aber schon Probleme eines komplexen Zusammenspiels. Oder andersrum, wenn du viele optimale Lösungen kombinierst, muss das Gesamtsystem nicht unbedingt optimal sein (Pareto-Suboptimalität), womit wir dann wieder bei den Kompromisslösungen wären.
Gruß