私の .NET アプリケーションでは、一連のセンサー イベントを再生する必要があります。そこで、これらのイベントを発生させるスレッドを作成しました (通常は約 1 ~ 4 ミリ秒ごと)。このスレッドにループを実装しThread.Sleep(...)
、イベント間でスレッドをスリープ状態にしていました。
基本的には次のようになります。
void RunThread() {
var iter = GetAllEvents().GetEnumerator();
if (!iter.MoveNext()) {
return;
}
DateTime lastEventTime = iter.Current.Timestamp;
FireEvent(iter.Current);
while (iter.MoveNext()) {
MyEvent nextEvent = iter.Current;
int timeout = (int)(nextEvent.Timestamp - lastEventTime).TotalMilliseconds;
Thread.Sleep(timeout);
FireEvent(nextEvent);
lastEventTime = nextEvent.Timestamp;
}
}
さて、私の問題はThread.Sleep()
、指定されたタイムアウトを尊重する場合とそうでない場合があることです。
StopWatch
スリープに実際にかかった時間のチェックを追加しました (上記のコードには表示されていません)。以下にいくつかの結果を示します。
Expected timeout of 1 ms but got 15 ms.
Expected timeout of 2 ms but got 13 ms.
Expected timeout of 3 ms but got 15 ms.
Expected timeout of 2 ms but got 13 ms.
Expected timeout of 1 ms but got 13 ms.
Expected timeout of 1 ms but got 15 ms.
Expected timeout of 2 ms but got 13 ms.
Expected timeout of 2 ms but got 40 ms.
なぜThread.Sleep()
「ランダムに」振る舞うのですか?
ノート:
- このスレッドの実行中、Windows タスク マネージャーは CPU 使用率を表示しません。
- 動作はランダムに変化しますが、少なくとも数秒間持続します。たとえば、スレッドを開始すると、正常に実行されます。次回はずっと遅くなります。次回は数秒間高速で実行されますが、速度が低下するか、その逆になります。
更新:Sleep
がどのように動作するかを示す擬似コードを次に示します。
bool ChooseRespectTimeout() {
if (this.notYetChosen) {
this.respectTimeout = ChooseRandomly()
this.notYetChosen = false
reset this.notYetChosen after random time period
}
return this.respectTimeout
}
void Sleep(int timeout) {
if (ChooseRespectTimeout())
Thread.Sleep(timeout)
else
Thread.Sleep(timeout * 10)
}