5

ゲートキーパータスクを使用して共有リソースにアクセスする設計に取り組んでいます。私が今持っている基本的な設計は、ゲートキーパータスクが受信している単一のキューと、それに要求を入れる複数のタスクです。

これはメモリが制限されたシステムであり、FreeRTOS(Cortex M3ポート)を使用しています。

問題は次のとおりです。これらの要求を非同期的に処理するのはかなり簡単です。要求元のタスクは要求をキューに入れ、ビジネス、ポーリング、処理、または他のイベントの待機を行います。これらのリクエストを同期的に処理するには、リクエストが処理されると、ゲートキーパーがそのリクエストを呼び出したタスクをウェイクアップできるように、リクエストするタスクがブロックするメカニズムが必要です。

私が考えることができる最も簡単な設計は、各リクエストにセマフォを含めることですが、メモリの制限とFreeRTOSのセマフォのサイズがかなり大きいことを考えると、これは実用的ではありません。

私が思いついたのは、タスクの一時停止とタスクの再開機能を使用してタスクを手動でブロックし、要求が完了したときにタスクを再開できるゲートキーパーにハンドルを渡すことです。ただし、サスペンド/レジュームにはいくつかの問題があり、私はそれらを避けたいと思っています。1回の再開呼び出しは、他の呼び出しによって何度中断されてもタスクをウェイクアップし、これにより望ましくない動作が発生する可能性があります。

一時停止/再開方法を示すためのいくつかの単純な疑似C。

void gatekeeper_blocking_request(void)
{
     put_request_in_queue(request);
     task_suspend(this_task);
}

void gatekeeper_request_complete_callback(request)
{
     task_resume(request->task);
}

当面使用する予定の回避策は、非同期呼び出しを使用し、各要求タスクに完全にブロッキングを実装することです。ゲートキーパーは、操作が完了すると、提供されたコールバックを実行します。その後、タスクのメインキューや特定のセマフォ、または必要なものにポストできます。リクエストのブロック呼び出しを行うことは本質的に便利な機能であるため、各リクエストタスクはこれを実装する必要はありません。

タスク固有のブロッキングを示すための疑似Cですが、これは各タスクに実装する必要があります。

void requesting_task(void)
{
     while(1)
     {
         gatekeeper_async_request(callback);
         pend_on_sempahore(sem);
     }
}

void callback(request)
{
     post_to_semaphore(sem);
}

おそらく最善の解決策は、ゲートキーパーとAPIにブロッキングを実装せず、各タスクにそれを処理させることです。ただし、これにより各タスクのフローが複雑になり、回避できると期待していました。ほとんどの場合、すべての呼び出しは、操作が終了するまでブロックする必要があります。

私が見逃しているいくつかの構造、または私がグーグルできるこのタイプの問題のより良い用語はありますか?私の検索では、このようなものは見つかりませんでした。

追記-ゲートキーパータスクの2つの理由:

  1. 大きなスタックスペースが必要です。この要件を各タスクに追加するのではなく、ゲートキーパーは、必要なすべてのメモリを備えた単一のスタックを持つことができます。

  2. リソースはCPUで常にアクセスできるとは限りません。CPU内のタスクだけでなく、CPU外のタスクも同期しています。

4

2 に答える 2

2

ミューテックスを使用して、ゲートキーパーをタスクではなくサブルーチンにします。

于 2010-11-09T18:04:42.047 に答える
2

この質問を投稿してから6年が経ちましたが、同期を必要な方法で機能させるのに苦労しました。使用されたOSコンストラクトのひどい悪用がいくつかありました。このコードを更新することは機能しますが、乱用を減らすことを検討したので、これを処理するためのより洗練された方法を検討しました。FreeRTOSはまた、過去6年間に多くの機能を追加しましたが、そのうちの1つは、同じことを実現するための軽量な方法を提供すると私は信じています。

タスクへの直接通知

私の最初の提案された方法を再考する:

void gatekeeper_blocking_request(void)
{
     put_request_in_queue(request);
     task_suspend(this_task);
}

void gatekeeper_request_complete_callback(request)
{
     task_resume(request->task);
}

この方法が回避された理由は、FreeRTOSタスクのサスペンド/レジューム呼び出しがカウントされないため、1回のレジューム呼び出しで複数のサスペンド呼び出しが無効になるためです。当時、アプリケーションは一時停止/再開機能を使用していたため、これは現実的な可能性でした。

FreeRTOS 8.2.0以降、Direct-to-task通知は、基本的に軽量の組み込みのタスクに組み込まれたバイナリセマフォを提供します。通知がタスクに送信されるときに、通知値が設定される場合があります。この通知は、通知されたタスクがのバリアントを呼び出すまで休止状態xTaskNotifyWait()になります。または、すでにそのような呼び出しを行っている場合はウェイクアップされます。

上記のコードは、次のように少し作り直すことができます。

 void gatekeeper_blocking_request(void)
 {
      put_request_in_queue(request);
      xTaskNotifyWait( ... );
 }

 void gatekeeper_request_complete_callback(request)
 {
      xTaskNotify( ... );
 }

これはまだ理想的な方法ではありません。タスク通知が他の場所で使用されている場合、サスペンド/レジュームで同じ問題が発生する可能性があります。この場合、タスクは予期しているものとは異なるソースによってウェイクアップされます。私にとって、それは新しい機能だったので、改訂されたコードでうまくいくかもしれません。

于 2016-08-30T19:06:24.803 に答える