Sehr vereinfacht könnte es so funktionieren:
- Erstellen Sie einen periodisch wartenden Timer mit einer vernünftig kleinen Wartezeit (vielleicht 100ms). Holen Sie einen "letzten" Wert für jeden relevanten Prozess, indem Sie
GetProcessTimes
einmal.
- Endlosschleife, Blockierung des Timers.
- Jedes Mal, wenn Sie aufwachen:
- si
GetProcessAffinityMask
0 zurückgibt, rufen Sie SetProcessAffinityMask(old_value)
. Das bedeutet, dass wir diesen Prozess in unserer letzten Iteration angehalten haben und ihm nun eine Chance geben, erneut zu laufen.
- sonst aufrufen
GetProcessTimes
um den "aktuellen" Wert zu erhalten
- aufrufen
GetSystemTimeAsFileTime
- Berechnung des Deltas durch Subtraktion des letzten vom aktuellen Wert
cpu_usage = (deltaKernelTime + deltaUserTime) / (deltaTime)
- wenn das mehr ist, als Sie wollen aufrufen
old_value = GetProcessAffinityMask
gefolgt von SetProcessAffinityMask(0)
was den Prozess offline schaltet.
Dies ist im Grunde eine sehr primitive Version des Schedulers, der im Kernel läuft und im Userland implementiert ist. Er versetzt einen Prozess für eine kleine Zeitspanne "in den Schlaf", wenn er mehr CPU-Zeit verbraucht hat, als Sie für richtig halten. Eine ausgefeiltere Messung, die vielleicht über eine Sekunde oder 5 Sekunden hinausgeht, wäre möglich (und wahrscheinlich wünschenswert).
Sie könnten versucht sein, stattdessen alle Threads des Prozesses zu unterbrechen. Es ist jedoch wichtig no mit den Prioritäten zu spielen und no zu verwenden SuspendThread
wenn Sie nicht genau wissen, was ein Programm tut, da dies leicht zu Deadlocks und anderen unangenehmen Nebeneffekten führen kann. Denken Sie zum Beispiel daran, einen Thread anzuhalten, der einen kritischen Abschnitt hält, während ein anderer Thread noch läuft und versucht, dasselbe Objekt zu erwerben. Oder stellen Sie sich vor, Ihr Prozess wird mitten in der Suspendierung von einem Dutzend Threads ausgelagert, so dass die Hälfte von ihnen läuft und die andere Hälfte tot ist.
Wenn die Affinitätsmaske auf Null gesetzt wird, bedeutet dies lediglich, dass von nun an kein einzelner Thread des Prozesses mehr Zeitscheiben auf einem beliebigen Prozessor erhält. Das Zurücksetzen der Affinität gibt - atomar, zur gleichen Zeit - allen Threads die Möglichkeit, wieder zu laufen.
Unglücklicherweise, SetProcessAffinityMask
gibt die alte Maske nicht als SetThreadAffinityMask
tut, zumindest laut der Dokumentation. Daher ist eine zusätzliche Get...
Anruf notwendig ist.