{"id":580,"date":"2010-01-23T20:39:22","date_gmt":"2010-01-23T19:39:22","guid":{"rendered":"http:\/\/blog.m-ri.de\/?p=580"},"modified":"2010-01-16T13:08:42","modified_gmt":"2010-01-16T12:08:42","slug":"was-denn-nun-switchtothread-sleep0-sleep1-2","status":"publish","type":"post","link":"http:\/\/blog.m-ri.de\/index.php\/2010\/01\/23\/was-denn-nun-switchtothread-sleep0-sleep1-2\/","title":{"rendered":"Was denn nun SwitchToThread(), Sleep(0), Sleep(1)?"},"content":{"rendered":"<p>Was macht man, wenn man keine Wait-Funktionen verwenden will, aber dennoch m\u00f6chte, dass ein anderer Thread weiterarbeiten kann. Zum Beispiel, weil man einen Spinlock implementieren will.<\/p>\n<p>Nun es gibt insgesamt vier Methoden die durch das Netz geistern.<br \/>\nIch gehe mal der H\u00e4ufigkeit nach, die so in manchen Code-Samples finde:<\/p>\n<h3>1. __noop;<\/h3>\n<p>Wenn der Lock kurz ist, scheint es das beste zu sein, einfach die Schleife weiterlaufen zu lassen und zu hoffen, dass der ein Thread auf einem anderen Prozessor, die Ressource freigibt. Das eignet sich wirklich nur, wenn die Zeitdauer der Sperre als extrem kurz anzusehen ist und eine hohe Anzahl von Prozessoren zur Verf\u00fcgung steht.<br \/>\nNach allen Test, die ich gemacht habe, sollte man aber von dieser Art des Wartens bei einem Spinlock absehen. Es schiebt die Leistung des Kerns auf 100% und bringt nichts.<\/p>\n<h3>2.\u00a0 Sleep(0);<\/h3>\n<p>Lies sich gut. Schlafe aber eben nicht lange. Man hat auch schon irgendwo gelesen, dass durch diese Methode der Rest der Zeitscheibe dieses Threads aufgegeben wird und ein anderer Thread an die Reihe kommt.<br \/>\nLeider stimmt das nicht ganz \u2757<br \/>\nLiest man die <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms686298(VS.85).aspx\">Doku<\/a> genau steht da aber:<\/p>\n<blockquote><p>A value of zero causes the thread to relinquish the remainder of its time slice to any other thread of equal priority that is ready to run. If there are no other threads of equal priority ready to run, the function returns immediately, and the thread continues execution.<\/p><\/blockquote>\n<p>\ud83d\ude2e Threads mit h\u00f6herer oder niedriger Prio haben also nichts davon.<\/p>\n<p>Besonders eklig wird das ganze gerade wenn man Threads unterschiedlicher Prio hat, die hier gegeneinander laufen. <em>Sleep(0);<\/em> f\u00fchrt in diesem Fall zu einerunn\u00f6tigen Prozessorlast und eben nicht dazu, dass die Zeitscheibe abgegeben wird. Der Prozess kommt sofort wieder an die Reihe und spin-t weiter.<\/p>\n<h3>3. SwitchToThread();<\/h3>\n<p>OK. Seit <em>Windows 2000<\/em> gibt es diese nette neue Funktion. Damit wird ein anderer Thread aktiv. Egal was f\u00fcr eine Prio er hat. Aber auch diese Funktion tut evtl. nicht genau das was man will.<br \/>\nAuch hier stecken die T\u00fccken im Detail der <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms686352(VS.85).aspx\">Doku<\/a>:<\/p>\n<blockquote><p>The yield of execution is limited to the processor of the calling thread. The operating system will not switch execution to another processor, even if that processor is idle or is running a thread of lower priority.<\/p><\/blockquote>\n<p>Sollte also der Thread, auf den man wartet auf dem anderen Prozessor laufen, so profitiert der nicht von dem Aufruf von <em>SwitchToThread<\/em>.<\/p>\n<h3>4. Sleep(1):<\/h3>\n<p>Hiermit erreicht man wirklich was man m\u00f6chte. Man gibt seine Timeslice auf und erstmal sind die anderen dran.<\/p>\n<h3>Mein pers\u00f6nliches Fazit:<\/h3>\n<p>Nach meinen Recherchen ist <em>Sleep(1); <\/em>der vern\u00fcnftigste Weg seine Zeitscheibe abzugeben. Und nach meinem Daf\u00fcrhalten ist ein <em>__noop; <\/em>strickt zu vermeiden. Die Performance ist grottenschlecht.<br \/>\nDas ganze Verhalten h\u00e4ngt extrem auch von den Umst\u00e4nden ab: Zahl der Theads, H\u00e4ufigkeit der Kollision, Anzahl verf\u00fcgbare Prozessoren, Verteilung der Priorit\u00e4ten, Allgemeine Belastung des Systems, Zeitdauer der Sperre etc.<\/p>\n<p>Ich habe mit einigen Parametern gespielt und auch ein kleines Sample gebaut, dass alle 4 oben genannten Funktionen durchprobiert und in dem man auch mit anderen Faktoren (Priorit\u00e4t etc.) spielen kann.<br \/>\nEs zeigte sich, dass <em>Sleep(1);<\/em> am effektivsten war. Aber dicht auf gefolgt von <em>Sleep(0);<\/em>, was mich doch etwas \u00fcberraschte.<\/p>\n<p>Allerdings f\u00fchren schon kleinste \u00c4nderungen (Lockdauer, Zahl der Prozessoren, Spielen mit der Priorit\u00e4t) zu anderen Ergebnissen.<br \/>\nInteressant ist vor allem das Spielen mit den Priorit\u00e4ten. Man soll nicht glauben, das ein Thread selbst mit niedrigster Prio noch relativ h\u00e4ufig Arbeit bekommt.<\/p>\n<p>Viel Spa\u00df beim Spielen mit dem Code <a href=\"http:\/\/blog.m-ri.de\/wp-content\/uploads\/2010\/01\/SleepTest.zip\">SleepTest<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Was macht man, wenn man keine Wait-Funktionen verwenden will, aber dennoch m\u00f6chte, dass ein anderer Thread weiterarbeiten kann. Zum Beispiel, weil man einen Spinlock implementieren will. Nun es gibt insgesamt vier Methoden die durch das Netz geistern. Ich gehe mal der H\u00e4ufigkeit nach, die so in manchen Code-Samples finde: 1. __noop; Wenn der Lock kurz &hellip; <a href=\"http:\/\/blog.m-ri.de\/index.php\/2010\/01\/23\/was-denn-nun-switchtothread-sleep0-sleep1-2\/\" class=\"more-link\"><span class=\"screen-reader-text\">\u201eWas denn nun SwitchToThread(), Sleep(0), Sleep(1)?\u201c <\/span>weiterlesen<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[3,9,2],"tags":[370,218,62,59,61,89],"class_list":["post-580","post","type-post","status-publish","format-standard","hentry","category-programmieren","category-sonstiges","category-windows-api","tag-c","tag-multithreading","tag-threads","tag-win32","tag-winapi","tag-windows"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/posts\/580","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/comments?post=580"}],"version-history":[{"count":1,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/posts\/580\/revisions"}],"predecessor-version":[{"id":585,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/posts\/580\/revisions\/585"}],"wp:attachment":[{"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/media?parent=580"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/categories?post=580"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/blog.m-ri.de\/index.php\/wp-json\/wp\/v2\/tags?post=580"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}