Sleep(1)
-
verzichtet einfach komplett auf diese sleep scheisse. es gibt immer eine bessere lösung.
-
Als da wäre?
Du kommst jedenfalls um Sleep bzw. SwitchToThread nicht herum, wenn du einen nicht-blockierenden Message Loop benötigst und nicht gleichzeitig mit 100% Auslastung andere Prozesse blockieren willst.
-
ewoi schrieb:
verzichtet einfach komplett auf diese sleep scheisse. es gibt immer eine bessere lösung.
Nein.
(außer vielleicht SleepEx)
-
Kann man das nicht alles mit Timern machen?
-
groovemaster schrieb:
Als da wäre?
Du kommst jedenfalls um Sleep bzw. SwitchToThread nicht herum, wenn du einen nicht-blockierenden Message Loop benötigst und nicht gleichzeitig mit 100% Auslastung andere Prozesse blockieren willst.
Das war wohl so bei Windows 3.x. Für zeitintensive Aufgaben verwendet man heutzutage Workerthreads und Events. Andere Prozesse werden normalerweise nur blockiert bei falscher Verwendung von SetPriorityClass oder SetThreadPriority. Eine Message-loop benötigt keine Sleep-Anweisung, das System legt Deinen Process automatisch schlafen, wenn keine Messages anliegen.
-
groovemaster schrieb:
Jochen Kalmbach schrieb:
Sleep(0) => Prozessorauslastung wird nicht reduziert (Thread wird *nicht* schlafen gelegt)
Sleep(0) sorgt dafür, dass der aktuelle Thread seine restliche Prozessorzeit abgibt. Und das reicht vollkommen aus. Man muss den Thread nicht extra schlafen legen.
Naja, dass ist nur die halbe Wahrheit... die restliche Prozessorzeit wird nur abgegeben, wenn es einen anderen Thread gibt, der laufen will!
Somit bleibt aber hier die Prozessorlast immer auf "Vollast" (zumindest für einen Prozessor).
-
Naja, dass ist nur die halbe Wahrheit... die restliche Prozessorzeit wird nur abgegeben, wenn es einen anderen Thread gibt, der laufen will!
Somit bleibt aber hier die Prozessorlast immer auf "Vollast" (zumindest für einen Prozessor).Soweit ich weiss gibt Sleep(0) auch immer nur an threads mit gleicher (oder höherer) Priorität ab. Wenn es einen "runnable" thread gibt der aber eine niedrigere Priorität hat wird der keine Rechenzeit bekommen.
Sleep(0) reicht daher NICHT und ist BÖSE.p.S.: Sleep(1) wartet auch nicht unbedingt >= 10ms, obwohl man mit einem Delay von 10-20ms rechnen sollte, ggf. viel mehr, und auf otto-normal-system es ~15ms sein werden.
-
_mgs schrieb:
Das war wohl so bei Windows 3.x...
Nö, das ist heute immer noch so. Eine nicht-blockierende Nachrichtenschleife ohne Sleep(0), SwitchToThread, WaitMessage oder was auch immer, hat einen Prozess mit 100% CPU-Auslastung zur Folge. Natürlich friert das System dadurch nicht ein, wie es unter Win3.x teilweise der Fall war. Es werden trotzdem andere Prozesse dadurch eingebremst.
Jochen Kalmbach schrieb:
Naja, dass ist nur die halbe Wahrheit... die restliche Prozessorzeit wird nur abgegeben, wenn es einen anderen Thread gibt, der laufen will!
Somit bleibt aber hier die Prozessorlast immer auf "Vollast" (zumindest für einen Prozessor).Ein Prozessor hat _immer_ "Last". Es ist nur die Frage, ob der Prozessor durch Threads ausgelastet wird oder nicht. Und wenn nicht, sich dann in den "Leerlauf" begeben kann. Ich bin mir zwar nicht ganz sicher, aber ich glaube Energiesparfunktionen, wie zB CnQ von AMD, werden damit entsprechend geregelt. Und Sleep(0) reicht jedenfalls aus, um die CPU Zeit mindestens an den Leerlauf abzugeben. Es ist daher auch irrelevant, ob es einen anderen User Thread gibt, der laufen will.
hustbaer schrieb:
Soweit ich weiss gibt Sleep(0) auch immer nur an threads mit gleicher (oder höherer) Priorität ab. Wenn es einen "runnable" thread gibt der aber eine niedrigere Priorität hat wird der keine Rechenzeit bekommen.
Was ebenfalls irrelevant ist. Sleep(0) gibt nicht an "irgendjemanden" ab. Sleep(0) sagt dem System lediglich, dass der aktuelle Thread seine verbleibende CPU Zeit nicht mehr benötigt und anderweitig verwendet werden kann. Und wenn das System irgendwann feststellt, dass ein Thread mit niedrigerer Priorität an der Reihe ist, dann wird es diesen auch ausführen. Egal ob irgendwo Sleep(0) verwendet wurde oder nicht.
hustbaer schrieb:
Sleep(0) reicht daher NICHT und ist BÖSE.
Nö, Sleep(0) ist nicht böse. Böse ist, einen uninitialisierten Zeiger zu dereferenzieren. Oder mit goto rückwärts zu springen. Sleep(0) ist, wenn überhaupt, dann in bestimmten Situationen uU nicht ausreichend.
-
Eine nicht-blockierende Nachrichtenschleife ohne Sleep(0), SwitchToThread, WaitMessage oder was auch immer, hat einen Prozess mit 100% CPU-Auslastung zur Folge. Natürlich friert das System dadurch nicht ein, wie es unter Win3.x teilweise der Fall war. Es werden trotzdem andere Prozesse dadurch eingebremst.
Das ist schlichtweg falsch. Eine Standardwarteschleife a la
MSG msg; while( GetMessage( &msg, NULL, 0, 0 ) ) { TranslateMessage( &msg ); DispatchMessage( &msg ); }
erzeugt keine nennenswerte Prozessorlast. Aus der Doku zu GetMessage:
"Unlike GetMessage, the PeekMessage function does not wait for a message to be posted before returning."
Wie Du siehst, kommt GetMessage erst zurück, wenn eine neue Nachricht für Dein Programm vorliegt - vorher tut sich gar nichts.
Wenn Du es nicht glaubst, schreib einfach ein kleines Programm mit dieser Messageloop und überprüfe die Prozessorlast.
-
Nö, Sleep(0) ist nicht böse.
Sleep ist vielleicht nicht böse - aber die häufige Verwendung dieser Funktion deutet zumindest auf Faulheit oder mangelnde Kenntnisse beim Programmieren hin. Sleep wird gerne eingesetzt, wenn Threads Ergebnisse pollen sollen und der Programmierer sich an Signalisierungsobjekte und Wartefunktionen nicht herantraut.
Wer Threads und Signale sinnvoll einsetzt, benötigt kein Sleep.
-
_mgs schrieb:
Das ist schlichtweg falsch.
Nö, ist es nicht. Dein Beispiel hat keine nicht-blockierende Nachrichtenschleife, denn wie du schon selbst festgestellt hast, geht es im Thread erst weiter, wenn eine Nachricht vorliegt. Nicht-blockierend bedeutet natürlich eine Schleife mit PeekMessage.
_mgs schrieb:
Sleep ist vielleicht nicht böse - aber die häufige Verwendung dieser Funktion deutet zumindest auf Faulheit oder mangelnde Kenntnisse beim Programmieren hin. Sleep wird gerne eingesetzt, wenn Threads Ergebnisse pollen sollen und der Programmierer sich an Signalisierungsobjekte und Wartefunktionen nicht herantraut.
Darum geht es überhaupt nicht. Für Multithreading sollte man natürlich auf sinnvolle Signalisierungsobjekte zurückgreifen. Hier ging es ausschliesslich um Sleep und die damit verbundene CPU Last des jeweiligen Threads. Und Sleep(1) macht nunmal keinen Sinn, wenn es einem einzig und allein um den Effekt von Sleep(0) geht.
-
Ok, ich hatte Deine Aussage "Eine nicht-blockierende Nachrichtenschleife" fälschlicherweise verstanden als "Eine nicht das System blockierende Nachrichtenschleife".
-
groovemaster schrieb:
Was ebenfalls irrelevant ist. Sleep(0) gibt nicht an "irgendjemanden" ab. Sleep(0) sagt dem System lediglich, dass der aktuelle Thread seine verbleibende CPU Zeit nicht mehr benötigt und anderweitig verwendet werden kann. Und wenn das System irgendwann feststellt, dass ein Thread mit niedrigerer Priorität an der Reihe ist, dann wird es diesen auch ausführen. Egal ob irgendwo Sleep(0) verwendet wurde oder nicht.
Sleep(0) sagt dem Scheduler bloss dass er wieder laufen darf. Wenn der Scheduller keinen Thread mit gleicher oder höherer Priorität findet kommt der selbe Thread der Sleep(0) aufgerufen hat *sofort* wieder dran, "seine verbleibende CPU Zeit" wird *nicht* einen Thread mit niedrigerer Priorität "geschenkt".
Und wenn das System irgendwann feststellt, dass ein Thread mit niedrigerer Priorität an der Reihe ist, dann wird es diesen auch ausführen.
Genau das wird der Scheduler *nie* entscheiden solange ein Thread (pro CPU/Core/HT-Unit) in einer "Sleep(0) Schleife" hängt.
MSDN schrieb:
Every thread in Windows has a base priority level determined by the thread's priority value and the priority class of its owning process. The operating system uses the base priority level of all executable threads to determine which thread gets the next slice of CPU time. Threads are scheduled in a round-robin fashion at each priority level, and only when there are no executable threads at a higher level will scheduling of threads at a lower level take place.
Probier es aus wenn du es mir nicht glaubst.
Von daher ist Sleep(0) an den Stellen wo man es üblicherweise findet (spinlock, polling) "böse" weil es Threads mit niedrigerer Priorität sämtliche CPU Zeit klaut.
---
Dass "Sleep(0)" nicht "böse" ist wenn es nicht in einer engen Schleife ausgeführt wird ist schon klar, bloss findes man es meistens in engen Schleifen. So Konstrukte wie "while(!expired()) Sleep(0);" hab ich schon viel zu oft gesehen. Dass das unsauberster Code^3 ist ist auch klar, aber wenn ich schon keinen sauberen Code haben kann (warum auch immer - und Gründe gibts reichlich, meistens Zeitdruck) dann lieber ein Sleep(1) an der Stelle als ein Sleep(0).
-
groovemaster schrieb:
Was ebenfalls irrelevant ist. Sleep(0) gibt nicht an "irgendjemanden" ab. Sleep(0) sagt dem System lediglich, dass der aktuelle Thread seine verbleibende CPU Zeit nicht mehr benötigt und anderweitig verwendet werden kann. Und wenn das System irgendwann feststellt, dass ein Thread mit niedrigerer Priorität an der Reihe ist, dann wird es diesen auch ausführen. Egal ob irgendwo Sleep(0) verwendet wurde oder nicht.
Da täuschst Du Dich aber gewaltig. Ein "Sleep(0)" stellt nur den aktuellen Thread ganz nach hinten in die Queue für diese Priorität und ruft dann den Scheduler auf.
Wenn jetzt natürlich ein anderer Thread mit der gleichen Priorität vorhanden ist, wird dieser für die restliche Time-Slice ausgeführt. Aber es kommen nie Threads dran mit niedriger Priorität!
(ok, es gibt da so noch ein paar Scheduler Tricks mit dynamischer Priorität, aber das würde zu weit führen).Das ganze ist auch simplen nachzuvollziehen und da muss man aich gar nicht so lange drüber Diskutieren:
#include <windows.h> #include <tchar.h> int _tmain(void) { while(true) { Sleep(0); } }
=> 100% CPU Auslastung (bei 1-Prozessor-System).
Lies doch bitte mal "Inside Windows Internals 4th Edition":
http://www.sysinternals.com/WindowsInternals.html
-
hustbaer schrieb:
Von daher ist Sleep(0) an den Stellen wo man es üblicherweise findet (spinlock, polling) "böse" weil es Threads mit niedrigerer Priorität sämtliche CPU Zeit klaut.
Es ist nicht nur unsauberer Code, sondern wirklich böse!!!
Was man damit heraufbeschwört ist das sog. "Priority Inversion"!
http://en.wikipedia.org/wiki/Priority_inversionFolgendes Szenario:
Ein Thread mit Prio 11 wartet auf eine Resource (z.B. Event), welcher von einem Thread mit Prio 4 gerade gehalten wird.
Nun gibt es den Thread von "groovemaster" mit Prio 7, welcher ein "Sleep(0)" eingebaut hat und gerade anfängt zu laufen.
Was passiert:
Der Thread mit Prio 4 wird nie wieder drankommen und somit wird auch der Thread mit Prio 11 blokiert.
Fazit: Wir haben sozusagen einen "Dead-Lock", der von groovemaster verursacht wurde!(ok, das Windows-OS hat für einen solchen Fall im dnymaischen Prio-Bereich auch eine akzeptable Lösung... wer kennt sie?)
War vielleicht groovemaster an der Software-Entwicklung für den "Mars Pathfinder" beteiligt!? Da ist nämlich genau das passiert
-
ok, das Windows-OS hat für einen solchen Fall im dnymaischen Prio-Bereich auch eine akzeptable Lösung... wer kennt sie?)
Ich
Sind auch 2 verschiedene -- Win9x vs. WinNT Schiene machen das anders.
-
Jochen Kalmbach schrieb:
#include <windows.h> #include <tchar.h> int _tmain(void) { while(true) { Sleep(0); } }
=> 100% CPU Auslastung (bei 1-Prozessor-System).
Wir reden hier aber schon über WinAPI und nicht Konsole, oder? Eine WinAPI Anwendung mit Sleep(0) hat jedenfalls keine 100% CPU Auslastung, da kannst du dich noch so quer stellen, das _ist_ so. Und was ihr mit eueren Prioritäten habt, ist mir auch unklar. Darum geht es überhaupt nicht. Alles was ich gesagt habe, ist, dass wer Sleep(1) verwendet, genauso gut Sleep(0) verwenden kann. Da ändert auch nichts daran, dass durch Sleep uU Probleme entstehen können. Denn dann sind sie in beiden Fällen vorhanden.
Und zum Thema Deadlock: so weit ich weiss, können diese hier nur entstehen, wenn es zwischen dem Thread mit höherer Priorität und dem Thread mit niedrigerer Priorität eine Abhängigkeit gibt, zB weil der eine auf den anderen wartet. Aber dass für solche Geschichten sowieso entsprechende Synchronisationsobjekte (Event, Mutex, Semaphore, etc.pp) verwendet werden sollte, hatten wir ja längst geklärt. Also regt euch mal nicht so künstlich auf und erzählt von Sachen, die sowieso nie zur Diskussion standen.@Jochen
Das mit dem Buch war wohl ein Scherz, oder?
-
groovemaster schrieb:
Wir reden hier aber schon über WinAPI und nicht Konsole, oder? Eine WinAPI Anwendung mit Sleep(0) hat jedenfalls keine 100% CPU Auslastung, da kannst du dich noch so quer stellen, das _ist_ so.
Dann solltest Du es ganz dringend mal ausprobieren... oder hier mal ein komplettes Beispiel posten!
Console oder WinApp spielt für den Scheduler keine Rolle... davon kennt der nix...
#include <windows.h> #include <tchar.h> int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) //int _tmain(void) { while(true) { Sleep(0); } }
groovemaster schrieb:
Alles was ich gesagt habe, ist, dass wer Sleep(1) verwendet, genauso gut Sleep(0) verwenden kann.
Und das ist absolut falsch, da die Änderung des Parameters von 0 auf >0 eine massiven Unterschied macht!
(Sleep(1) macht nämlich genau das was Du denkst, was Sleep(0) machen würde!)
-
@Jochen Kalmbach:
Wie siehts eigentlich mit SwitchToThread aus? Die Doku ist da ja nicht sonderlich klar, liest sich für mich aber so als ob da auch Threads mit niedrigerer Priorität drankommen würden.Kann man SwitchToThread reinen Gewissens für Spinlocks verwenden?
-
SwitchToThread hat prinzipiell den gleichen Effekt wie Sleep(0).
PS: Ein Sleep/SwitchToThread macht i.d.R. fast nie Sinn. Synchronisationen sollte man immer über Events/Semaphore/Interlockes machen...