RtSleep()の限界(誤った例)まとめ INTime [INtime]
以下のコードが正しく動作しない理由まとめ
while(1){
// 1ms周期でデバイスの状態を確認する。
RtSleep( 1 );
bFlg = inbyte( wBase + IRQ_TAG );
bState = inbyte( wBase + STATE_TAG );
}
上のコードは正しく意図どおり動作いたしません。これはINtimeの高レベルティック周期が10msであることに関連します。RtSleep()に指定できる最短周期は10msです。RtSleep( 1 ) は事実上 RtSleep( 0 )ということになり、指定した1msの周期で動作することにはならないのです。
さらに RtSleep( 15 ) とした場合、 この指定により意図どおり15ms待機を行うわけではありません。これは15msという時間値を高レベルティック値に変換するためです。
高レベルティックへの変換とは、指定値を高レベルティック周期 10ms単位に丸 めるということです。すなわちこの場合、周期単位10に満たない端数の5は切捨て されるということを意味します。そして実行時 にはRtSleep(10)のように動作します。
対応方法
1. 低レベルスリープ knRtSleep()
1msの周期で処理を行う必要がある場合もあるでしょう。
そういった場合、低レベル関数であるknRtSleep()を使用します。
knRtSleep( UsecsToKticks( 1000 ) ); // 1msのスリープ要求
ただしカーネルティックが1000us以下に設定されている必要があります。たとえばknRtSleep(100)のようにカーネルティック値よりも小さな値に設定しても、100usのスリープとはなりません。実際は以下のようにカーネルティックでの動作となってしまいます。
◆INtime 3.0 設定可能なカーネルティック値
100us
125us
200us
250us
500us
1000us
2000us
5000us
10000us
- カーネルティック=500usの場合
- knRtSleep( 1 ) は 約500usのスリープを意味します。
- カーネルティック=200usの場合
- knRtSleep( 1 ) は 約200usのスリープを意味します。
2. RtSleepEx()
INtime3.0バージョン以降では、㍉秒単位で時間指定が可能なRtSleepExコールが実装されています。このコールを含んだアプリケーションは、以前のINtimeバージョンで動作しませんのでご注意ください。
RtSleepEx( 6 ); // 6msのスリープ要求
参考サイト
INtimeがWindowsに与える弊害 [INtime]
リアルタイムスレッドの処理が長期化する場合は、Windowsに与えられる時間(リアルタイム制御の空き時間)が減少するのでWindowsの挙動が重く感じる、あるいはWindowsが全く動作しなくなる場合があります。しかしこれはリアルタイム処理を先制するという前提に基づくものであり、いわば当然の出来事です。
このような場合はCPUを高速化することでリアルタイムスレッドの処理時間短縮を試みるか、元来リアルタイムが必要な処理であるのかを改めて慎重に見極める必要があります
たとえば次のような処理をリアルタイムスレッドとして記述した場合は、Windowsを極端に重い状態に陥れるか、CPU性能次第ではWindowsを全く動作できない状態に陥れる場合もあります。
for( dwCount=0 ;dwCount<4000000 ;dwCount++ )
{
wData[dwCount] = dwCount;
}
IO制御の場合の対応
- ポーリング式から割り込み方式へ変更してみる。
- ループ内に、”knRtSleep( UsecsToKticks( 100 ) );”等のスリープ関数がある場合、間隔を長くしてみる。
参考サイト