2013年10月26日土曜日

今更Sleepについて書く事になろうとは・・・

どうも書かなくてはならないネタが出来てしまった。
マルチスレッドには欠かせないSleep(0)についてだ。
自分はSleep(0)を多用していた。
MSDNの記述によると
「中断時間として 0ms を指定してこの関数を呼び出すと、現在のスレッドは自らに割り当てられているタイムスライスの残りの部分を放棄します。」
という事なのだ。
つまり、「ここまででいいや」って時にSleep(0)を挟むと、他のスレッドが起動し始めるということだ。
これによって、OS全体の動きがスムーズになるはずなのだ。
Sleep(1)として1を入れる人も居るが、1についてはMSDNのどこにも記述が無い。

ところが・・・
最近作ったプログラムで、Sleep(0)を使ったところ、CPUの使用率が100%になってしまった。しかも単純なループで・・・
調べてみると、INTELの記述があった。
ちなみに日本語参考訳もある。
「Sleep(0) の呼び出しは、命令パスがかなり長く、約 1,000 サイクルも消費する ring3 から ring 0 への遷移があるり、プロセッサーは、この “スリープループ” が有効な作業を行っていると思い込む。さらに、無駄なエネルギー消費が起きてしまう。」

Core2やAMD64あたりのCPUでは普通にSleep(0)で動いていた筈なんだが・・・

そこで、INTELの推奨している方法は、_mm_pause() を使う事だ。
_mm_pause() はSSE2命令をサポートしていないシステムではnopになるらしい。 

INTELのサイトではサンプルが提供されているが古いシステムでnopになったら、あれだとCPUパワーを他のアプリに割り振ることが出来ないので駄目じゃないのかと思う。

最後に、INTELの記述に笑った
「我々は、数年にわたって調査と測定を行うことで、これらの問題に対処することができました。」

本当に数年かかったよ!

0 件のコメント: