Sleep(1)
-
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...
-
Sorry das ich mich da jetzt mal so 'reinschiebe', aber hab da auch mal ne kleine Frage...:
Ich verwende Sleep(n) (n mindestens > 100) um die Laufzeit meines Programms zuverbessern. Eini Thread meines Programms hat einen rechenintensiven Vorgang zu bewältigen, der sich vom Benutzer pausieren lässt, das ist so realisiert:// ... // in der Thread-Prozedur: // ... while(pThreadData->fPaused) // Variable ist volatile und wurde als Datenstruktur an den Thread übergeben (fPaused ist vom Typ bool) Sleep(100); // ...
Ist das sinnvoll ? Damit dürfte doch mehr Rechenzeit für andere Prozesse/Threads zur Verfügung stehen, oder?
(Hab mir nicht den gesamten Forum-Thread durchgelesen. )
-
CodeFinder schrieb:
Ist das sinnvoll ?
nö, nicht wirklich. nimm besser 'WaitForSingleObject()' für solche verschnaufpausen...
-
Ne, wirklich sinnvoll ist das nicht. Nimm lieber einen Event, auf den du mit WaitForSingleObject() warten kannst.
-
net schrieb:
CodeFinder schrieb:
Ist das sinnvoll ?
nö, nicht wirklich. nimm besser 'WaitForSingleObject()' für solche verschnaufpausen...
Huh?!, Aber worauf soll ich denn dann warten...auf den Haupthread ?
-
CodeFinder schrieb:
Huh?!, Aber worauf soll ich denn dann warten...?
auf was du willst. guckst du CStoll's posting...
-
Hm ok, verstehe ... ist nur irgendwie mehr Aufwand, ...aber danke .
-
CodeFinder schrieb:
net schrieb:
CodeFinder schrieb:
Ist das sinnvoll ?
nö, nicht wirklich. nimm besser 'WaitForSingleObject()' für solche verschnaufpausen...
Huh?!, Aber worauf soll ich denn dann warten...auf den Haupthread ?
Nein, auf einen Event, der ausgelöst wird, wenn der Nutzer den Pause-Modus beendet.
-
CStoll schrieb:
[...]Nein, auf einen Event, der ausgelöst wird, wenn der Nutzer den Pause-Modus beendet.
Jo und das wird im Hauptthread gesetzt, das meinte ich damit .
-
Jochen Kalmbach schrieb:
PS: Ein Sleep/SwitchToThread macht i.d.R. fast nie Sinn. Synchronisationen sollte man immer über Events/Semaphore/Interlockes machen...
Jo, das ist mir schon klar, danke
Es gibt halt Fälle wo man - weils manchmal einfacher ist - interlocked variablen pollt. Und in so einer Schleife macht dann ein Sleep(1) schon Sinn... bei einem spin-sleep-lock ala critical section isses natürlich wurscht, da spinnt man ja eh nicht lange.
-
_msg schrieb:
Zitat:
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.
---
CodeFinder schrieb:
Hm ok, verstehe ... ist nur irgendwie mehr Aufwand, ...aber danke .
q.e.d
-
@CodeFinder: Kannst Du Dich mal bei mir per Mail melden!?