DOBON.NET DOBON.NETプログラミング掲示板過去ログ

1mS周期で

  • 題名: 1mS周期で
  • 著者: bantou
  • 日時: 2005/12/02 17:03:24
  • ID: 14028
  • この記事の返信元:
    • (なし)
  • この記事への返信:
  • ツリーを表示
環境/言語:[Windows XP pro sp2 .NET C#]
分類:[.NET]


例えば、

while(true)
{
なんかの処理
System.Threading.Timer.Sleep(1); // 1mS
}

というような処理を行った場合、
実際の処理の間隔が1mSではなくて15mSぐらいになってしまいます。
スレッドセーフの状態で、
何とかこの部分を1mS周期間隔で行う方法は無いでしょうか?
  • 題名: Re[1]: 1mS周期で
  • 著者: NyaRuRu
  • 日時: 2005/12/03 1:06:18
  • ID: 14042
  • この記事の返信元:
  • この記事への返信:
  • ツリーを表示
> 実際の処理の間隔が1mSではなくて15mSぐらいになってしまいます。
> スレッドセーフの状態で、
> 何とかこの部分を1mS周期間隔で行う方法は無いでしょうか?

ハードウェア的な理由です.

timeBeginPeriod / timeEndPeriod API を使用してみてください.

------------
以下解説.

Windows はスレッドスケジューリングのトリガのひとつとしてハードウェアのタイマ割り込みを使用します.
Linux Kernel 2.6 など最近の OS ではデフォルトの割り込み間隔を 1 msec にするものも出てきましたが,Windows XP では 10 msec または 15 msec に設定されるのが一般的です.

http://www.microsoft.com/whdc/system/CEC/mm-timer.mspx

http://mowamowa.p.utmc.or.jp/~amedama/cgi-bin/wiki/wiki.cgi?page=Kernel%A5%E1%A5%E2+%BB%FE%B4%D6%B4%C9%CD%FD%CA%D4

何故この割り込み間隔が重要かというと,OS が待機状態のスレッドに制御を戻すかどうか判断するタイミングが,この割り込みのタイミングまで出来ないことがあるからです.

簡単のためシングルプロセッサ環境について考えましょう.あるスレッドが System.Threading.Timer.Sleep(1); によって CPU の使用権を放棄したとします.その後に実行権を得た別のスレッドがしばらく自発的に実行権を放棄しなかったと場合,次にカーネルが状況をチェックできるのはタイマ割り込みによって強制的に CPU の使用権がカーネルに移動したときになります.

このタイミングでカーネルは Sleep を行っていたスレッドをアクティブにする必要があることを認識し,スレッド優先度等に照らし合わせてこのスレッドをアクティブにするかどうかを決定します.

そして実際にこのスレッドの実行が再開されると,すぐにまた Sleep が行われることになります.この間の処理が十分高速に行われると,次の割り込み時刻は約 10msec から 15msec 後となり,これ以降はその間隔で繰り返し Sleep から処理が帰るように見えるかもしれません.

この割り込み間隔は timeBeginPeriod API によって変更できます.
間隔の下限値は timeGetDevCaps API によって取得できる TIMECAPS.wPeriodMin ですが,一般的な PIT 8254 が使用される環境では 1 msec が下限となるでしょう.(最近の AMD 環境などでは HPET が使用される可能性もあるのかもしれませんが,実機がないため未確認です)

この API はハードウェアの設定を変更するため,別のアプリケーションが割り込み間隔を変更してもその影響はシステム全体に及びます.手近なところでは Windows Media Player 10 が再生時に timeBeginPeriod を使用します.バックグラウンドで Windows Media Player 10 を使用しているときは 1msec 単位で Sleep から戻るように見えるかもしれません.

timeBeginPeriod で割り込み間隔を 1msec に指定しても,必ず Sleep から 1msec で戻るとは限りません.割り込みは Sleep が行われてから 1msec 後ではなく,単純に前回の割り込みから 1msec 後に起きるからです.
Sleep の 0.3msec 後と 1.3 msec 後に割り込みが発生する場合,Sleep から戻るのは 1.3 msec 後となる可能性があります.

また,スレッド優先度の関係で,割り込み後に CPU 使用権が必ず得られるとは限りません.優先度の高いスレッドが長時間 CPU を手放さなかった場合,Sleep から戻るのは 1msec より大きく後になるかもしれません.
  • 題名: Re[2]: 1mS周期で
  • 著者: bantou
  • 日時: 2005/12/03 11:26:27
  • ID: 14051
  • この記事の返信元:
  • この記事への返信:
    • (なし)
  • ツリーを表示
NyaRuRu 様回答ありがとうございます。

timeBeginEventとtimeEndEventを調べていたら、
timeSetEventを見つけました。

実は1mS周期に対する正確さは「極力早く」に近い状態なので、
目的としてはtimeSetEventの方があっているようです。
timeSetEventでTIME_PERIODICにCallBack関数を呼び出すことで、
今回の目的は果たせそうです。

どうもありがとうございました。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板