2010-11-18 7 views
6

私は、Visual Studio 2010とMingW(2つの独立したビルド環境として)を使用してWin32環境でリアルタイムプリエンプティブスケジューラをシミュレートしようとしている組み込みプログラマです。私はWin32スケジューリング環境で非常に緑色で、私がしようとしているものでレンガの壁に当たっています。リアルタイムの動作を達成しようとはしていません。実際のターゲットハードウェアと同じ順序と順序でシミュレートされたタスクを実行するだけです。優先順位に基づいて定義されたシーケンスにWin32スレッドスケジューリングを強制する

シミュレートされるリアルタイムスケジューラは、実行可能な最も優先度の高いタスク(スレッド)を常に実行するという簡単な目的を持っています。タスクがすぐに実行できるようになると、現在実行中のタスクの優先度が現在実行中のタスクよりも高い場合、そのタスクをプリエンプトする必要があります。タスクは、待機していた外部イベント、タイムアウト/ブロック時間/スリープ時間の期限が切れたために実行することができます。ティック割り込みによってタイムベースが生成されます。

このようなプリエンプティブな動作に加えて、タスクは、スリープまたは待機タイプの機能を実行しているため、タイムスライスを放棄するか、またはボランティアできます。

シミュレーションするリアルタイムスケジューラによって作成されたタスクごとに優先度の低いWin32スレッドを作成することでシミュレーションしています(スケジューラが実際の埋め込み対象で行うコンテキスト切り替えがスレッドによって効果的に行われます)疑似割り込みハンドラ(Win32イベントオブジェクトを使用してシミュレーションされたティック割り込みとそれに信号を送信する要求を処理する)としてのWin32スレッド、およびティック割り込みを生成する周辺装置をシミュレートするための優先度の高いWin32スレッド。

タスクスイッチが発生する必要があることを擬似割り込みハンドラが設定すると、SuspendThread()を使用して現在実行中のスレッドを一時停止し、ResumeThread()を使用して新しく選択したタスクを実行するスレッドを再開します。作成される可能性のある多くのタスクおよび関連するWin32スレッドのうち、そのタスクを管理するスレッドは、一度に中断状態になることはありません。

SuspendThread()が呼び出された直後に中断されたスレッドが中断し、割り込みが保留中であることを通知するイベントが通知されるとすぐに疑似割り込み処理スレッドが実行されることが重要ですが、これは動作I見ている。

私が既に回避している問題の例:タスク/スレッドがyieldイベントを生成すると、変数にラッチされ、割り込み処理スレッドが通知されます。擬似割り込み(yield)が必要です処理。今私がプログラミングに慣れているリアルタイムシステムでは、割込み処理スレッドは、スレッドに信号を送るスレッドよりも高い優先度を持つため、シグナルが送られることをすぐに実行することが期待されます。私がWin32環境で見ているのは、優先度の高いスレッドを通知するスレッドが、中断される前にしばらくの間継続しているということです - シグナルが送られた優先度の高いスレッドが実行を開始する前に、タスクは実際に実行を停止する - 私はどちらがわからない。いずれにしても、これは、Win32割り込みハンドリングスレッドにシグナルを通知した後、シグナルハンドラWin32スレッドブロックをセマフォ上に作成することで簡単に正しいことがあります。また、Win32スレッドハンドラの処理(ハンドシェイク)終了時にスレッドのブロックを解除します。スレッド同期を効果的に使用して、スケジューリングパターンを必要なものに強制します。私はこの目的のためにSignalObjectAndWait()を使用しています。

このテクニックを使用すると、シミュレートされているリアルタイムスケジューラが協調モードで機能しているが、プリエンプティブモードでは(必要に応じて)機能していない場合でも、

プリエンプティブなタスク切り替えの問題は、同じことを推測します。タスクが実際に実行を停止する前に中断するように指示された後、しばらくの間実行され続けるので、システムは一貫性のある状態タスクを実行するスレッドは中断します。しかし、プリエンプティブなケースでは、タスクがいつ起こるのか分からないため、セマフォを使用してWin32 theadが次回に再開されるまで継続するのを防ぐ同じテクニックは使用できません。

誰もがこの投稿を遠くに作りましたか?その長さで申し訳ありません!

私の質問は、以下のとおりです。

  • 私が起動し、サスペンドとレジュームスレッド関数が呼び出されていることをすぐにタスクを停止するためにWin32の(XP)のスケジュールを強制するにはどうすればよい - または - 私は高い優先度を強制する方法Win32スレッドは即座に実行を開始できます(ブロックされているオブジェクトが通知されます)。効果的に実行中のプロセスの再スケジュールをWin32に強制します。

  • タスク/スレッドの逐次実行パスにないイベントを待機するようにタスクを非同期に停止する方法はありますか。

  • シミュレータは、POSIX信号を使ってスレッドを効果的に中断させるLinux環境でうまく動作します.Win32には同等の機能がありますか?この長い記事を読むのに時間をとっている誰でも、このWin32の迷路を通して私のリアルタイムのエンジニアの手を保持することができます誰にも事前に特に感謝の

感謝。

答えて

5

独自のスケジューリングを行う必要がある場合は、スレッドの代わりにfibersを使用することを検討してください。ファイバは実行可能コードの別々のブロックであるという点でスレッドと似ていますが、ファイバはユーザコードでスケジュールできますが、スレッドはOSによってのみスケジュールされます。単一のスレッドが複数のファイバのスケジューリングをホストし、管理することができ、ファイバは互いにスケジュールすることさえできます。

+0

しかし、ファイバは複数のコアで同時に動作しません。 –

+0

チップをありがとう。私は明日ファイバーに関する参考資料を探します。 – Richard

+0

@ Zan:複数のファイバを1つのスレッドで実行することができ、複数のスレッドをコアごとに1つずつ実行できます。 –

1

まず、あなたのスレッドにはどのような優先度の値を使用していますか?

高優先度スレッドをTHREAD_PRIORITY_TIME_CRITICALに設定すると、すぐに実行されるはずです。リアルタイムプロセスに関連付けられたスレッドだけが優先度が高くなります。

第2に、一時停止と再開がすぐには起こっていないことをどのように知っていますか?これが問題だと確信していますか?

スレッドを強制的に停止させずに、待機コードを挿入することはできません。 SuspendThreadがあなたのために働いていない場合、これは助けにならないでしょう。

信号に最も近いのはおそらくQueueUserAPCで、次回スレッドが「アラート可能な待機状態」に入るときに実行するコールバックをスケジュールします。 SleepExまたはWaitForSingleObjectExなどと呼んでください。

1

@Anthony W - アドバイスありがとうございます。私はTHREAD_PRIORITY_ABOVE_NORMALでリアルタイムタスクをシミュレートしたWin32スレッドと、THREAD_PRIORITY_HIGHESTで擬似割り込みハンドラとティック割り込みジェネレータを実行したスレッドを実行していました。中断されたスレッドは、違いが生じた場合に備えてTHREAD_PRIORITY_IDLEに変更されました。私はTHREAD_PRIORITY_TIME_CRITICALを使用するようあなたの提案を試みましたが、残念ながらそれは何の違いもありませんでした。

あなたの質問に関しては、一時停止と再開が直ちに起こらないことが問題であることを確信しています。まあ、私はそうではありません。私がよく知らない環境では、私の最高の推測です。一時停止と再開の失敗に関する私の考えは、仕事が収穫されたときの私の観察からすぐに生じる。私がyieldを呼び出すと(信号[Win32イベントを使用する]優先度の高いWin32スレッドが次のリアルタイムタスクに切り替える)、yieldの後にブレークポイントを置くことができ、より高い優先順位のブレークポイントの前にヒットすることができます糸。イベントを通知するのが遅れて優先度の高いタスクが実行されているかどうか、またはスレッドとスレッドが実際に実行を停止するのを遅らせることで遅延が発生したかどうかは不明ですが、その動作は確実に確認されています。これはセマフォハンドシェイクを使用して修正されましたが、ティック割り込みによって引き起こされるプリエンプションでは実行できません。

リアルタイムタスクのスケジューリングシーケンスをチェックする一連のテストが失敗しているため、シミュレーションが期待どおり実行されていないことがわかりました。スケジューラに問題がある、またはテストに問題がある可能性は常にありますが、テストは実際のリアルタイムターゲットに失敗することなく数週間実行されるので、テストとスケジューラは問題ないと思うようになります。大きな違いは、ティック周波数が1ミリ秒のリアルタイム目標にありますが、Win32シミュレートされたターゲットでは15ミリ秒であり、それでもかなりのばらつきがあります。

@Remy-私は今日のファイバーについてかなり読んだことがあります。私の結論は、協調モードでスケジューラをシミュレートするためには完璧だということです。しかし、私が見ることができる限り、それらはファイバ自体がSwitchToFiber()関数を呼び出すことによってのみスケジューリングすることができます。スレッドがタイマーでブロックするか、定期的に実行されるようにスリープさせることができます。その時間に実行されていたファイバーを効果的にプリエンプトしますか?私が読んだことから、答えは「いいえ」です。なぜなら、1つのファイバをブロックすると、スレッド内で実行されるすべてのファイバがブロックされるからです。それを動作させることができれば、定期的に実行されるファイバーはSwitchToFiber()関数を呼び出して、次のファイバーを選択して一定期間スリープ状態にすることができますか?もう一度、私は答えがノーだと思う。別のファイバーに切り替えると、もはや実行されないので、次にファイバーがファイバーに戻ってくるまで、実際にSleep()関数を呼び出さないからです。繊維の仕組みが間違っている場合は、ここで私の論理を修正してください。

ファイバーを実行しているスレッドとは別に、独自のスレッドに定期的な機能が残っていれば機能すると思うが、(もう一度読んだところから)1スレッドが実行に影響を与えるとは思わない別のスレッドで実行されているファイバーの数。もしあなたが間違っていたら、ここで私の結論を訂正することができたら、私は再び感謝します。

1

[編集] - 以下のハックより簡単です - すべてのスレッドが同じCPUコアで実行されていることを確認しているようですが、問題は修正されています。唯一の問題は、CPUが100%近く稼動していることです。熱がそれに損害を与えるかどうかはわかりません。 [/編集]

アハ!私はこれを回避しようとしていると思うが、その醜い。しかし、醜さはポート層に保持されます。

私が今行っているのは、タスクを実行するためにスレッドが作成されるたびにスレッドIDを格納することです(作成されたリアルタイムタスクごとにWin32スレッドが作成されます)。次に、トレースマクロを使用して呼び出される以下の関数を追加しました。トレースマクロは、必要なものを実行するように定義することができ、この場合は非常に便利です。以下のコードのコメントが説明しています。シミュレーションは完璧ではなく、スレッドスケジューリングから既に外れているときはスレッドスケジューリングを修正しますが、最初は間違っていない方が望ましいですが、トレースマクロを配置すると、このソリューションはすべてのテストに合格します。

void vPortCheckCorrectThreadIsRunning(void) 
{ 
xThreadState *pxThreadState; 

    /* When switching threads, Windows does not always seem to run the selected 
    thread immediately. This function can be called to check if the thread 
    that is currently running is the thread that is responsible for executing 
    the task selected by the real time scheduler. The demo project for the Win32 
    port calls this function from the trace macros which are seeded throughout 
    the real time kernel code at points where something significant occurs. 
    Adding this functionality allows all the standard tests to pass, but users 
    should still be aware that extra calls to this function could be required 
    if their application requires absolute fixes and predictable sequencing (as 
    the port tests do). This is still a simulation - not the real thing! */ 
    if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) 
    { 
     /* Obtain the real time task to Win32 mapping state information. */ 
     pxThreadState = (xThreadState *) *((unsigned long *) pxCurrentTCB); 

     if(GetCurrentThreadId() != pxThreadState->ulThreadId) 
     { 
      SwitchToThread(); 
     } 
    } 
} 
関連する問題