トロンフォーラム

第4回 タスク間同期・通信機能2

メッセージバッファとメールボックス

前回に引き続き、RTOSが提供する同期の機能について説明します。

メッセージの送受信による同期

第3回タスク間での同期として「イベントフラグ」、「セマフォ」について説明しました。

イベントフラグおよびセマフォは、複数タスクで連携して処理を実行する場合や、排他制御する場合には非常に便利な機能です。しかし、タスク間の同期だけでなく、同時に情報を通知したいことがあります。例えば、あるタスクで処理した結果を基に別のタスクで処理したいとか、共有メモリを介さずにタスク間でデータ(T-Kernelでは「メッセージ」と呼びます)の送受信をしたいとか、開発するシステムによっていろいろな組み合わせが考えられます。

このような複数タスク間でデータを送受信することを「通信」と呼びます。また、同時に「同期」も行うために、「同期・通信」と呼ばれます。T-Kernelには以降で説明するメッセージバッファやメールボックス機能が用意されていますので、必要に応じて最適な同期機能を利用することで、効率の良いプログラムを開発できるようになっています。

図1 メッセージの送受信による同期・通信機能

図1 メッセージの送受信による同期・通信機能

メッセージバッファ (message buffer)

T-Kernelでは、メッセージの送受信ができる機能を複数用意していますが、その一つとしてメッセージバッファがあります。メッセージバッファは、可変長のメッセージを送受信することのできる同期・通信機能の一つです。送信側はメッセージを送受信のためのメッセージバッファ領域に格納し、受信する側はメッセージバッファ領域からメッセージを一つ取り出すことで同期・通信を実現しています。
メッセージバッファにメッセージが格納されていない場合にメッセージを受信しようとすると、受信待ち状態になります。一方で、メッセージバッファ領域に十分な空き領域がない場合にメッセージを送信しようとすると、送信待ち状態になります。

リスト1は「タスクAの処理は、タスクBで実行する処理 doWorkB() の結果を受け取り、その結果を doWorkA() で利用する」ようにメッセージバッファを利用してプログラミングした例です※1

※ 以下のサンプルプログラムはこちらからダウンロードできます。

tk_rcv_mbfがメッセージを受信する機能、tk_snd_mbfがメッセージを送信する機能です。

プログラムを動作させるとタスクAの方が先に実行を開始しますが、17行目(タスクAの中)にtk_rcv_mbfを入れてあるので、メッセージ受信待ちになり、ここで一旦処理を停止します。その後、タスクBが実行状態となります。タスクBが(doWorkBの処理を完了した後で)32行目のtk_snd_mbfを実行すると、タスク優先度高(=1)のタスクAがtk_rcv_mbfによる停止状態(T-Kernelで言う「待ち状態」)から戻り、doWorkAを実行できるようになります。

なお、T-Kernelではイベントフラグなどと同様に、予め利用するメッセージバッファの準備をしておく必要があります。これが46行目のtk_cre_mbf(メッセージバッファの生成)です。T-Kernelでは、目的に応じて複数のメッセージバッファを生成して利用することができます。

ここで示した同期方法は一例にすぎません。例えば、メッセージバッファ領域のサイズが0のメッセージバッファを生成すると、tk_snd_mbfでメッセージ送信待ち状態にすることも可能です。この場合、メッセージは送信側タスクが用意したバッファから、受信側タスクが用意したバッファへと直接コピーされます。

メッセージバッファを利用すると、ここで示した以外にも、さまざまな依存関係に合わせた同期・通信の機能が実現できます。

■メッセージバッファの生成  tk_cre_mbf (リスト1の46行目など)

メッセージバッファを生成します。

パラメータにはT_CMBF型の構造体へのポインタを指定します。構造体は以下のように定義されていて、メッセージバッファに関する情報を設定することができます。

必ず設定しなければならないのは mbfatr、bufsz、maxmsz の3つです。

リスト1の40行目では、以下の値を変数の宣言時に設定しています。

  • mbfatrには、TA_TFIFO を設定しています。
    ここではtk_rcv_mbfで送信タスクが待ち状態になる場合の並び順などを設定します。
    TA_TFIFO
    : メッセージ送信待ちタスクの待ち状態になる場合の並び順はFIFOにする。
    TA_TPRI
    : メッセージ送信待ちタスクの待ち状態になる場合の並び順は優先度順にする。
  • bufszには、0x10 を設定しています。
    この値は、メッセージバッファ領域のサイズ(バイト数)になります。
    この値を0に設定することで、tk_snd_mbfを使ってメッセージ送信待ち状態にすることが可能です。
  • maxmszには、0x4 を設定しています。
    この値は、メッセージの最大長(バイト数)になります。
    tk_snd_mbfでmaxmszを超えるサイズのメッセージを送信した場合、エラー(E_PAR)になります。

なお、メッセージバッファの生成に成功すると、tk_cre_mbfの戻値として、生成したメッセージバッファの識別子(メッセージバッファID)が返されます※2

■メッセージバッファへ送信  tk_snd_mbf (リスト1の32行目など)

メッセージバッファへメッセージを送信します。

第1引数には、メッセージバッファIDを指定します。

第2引数には、送信するメッセージの先頭アドレスを指定します。

第3引数には、送信するメッセージのサイズを指定します。

第4引数には、タイムアウト時間を指定します。一定時間待ってもメッセージ送信待ちが解除されない場合、タイムアウトエラーが発生してtk_snd_mbfが終了します。リスト1では待ち時間(数値)ではなくTMO_FEVRが指定されています。この場合、タイムアウトは発生しません。

■メッセージバッファからの受信  tk_rcv_mbf (リスト1の17行目など)

メッセージバッファからメッセージを受信します。

第1引数には、メッセージバッファIDを指定します。

第2引数には、受信するメッセージを入れるアドレスを指定します。

第3引数には、タイムアウト時間を指定します。一定時間待ってもメッセージ受信待ちが解除されない場合、タイムアウトエラーが発生してtk_rcv_mbfが終了します。リスト1では待ち時間(数値)ではなくTMO_FEVRが指定されています。この場合、タイムアウトは発生しません。

メールボックス (Mailbox)

メッセージを送受信できる機能は、複数用意されていますが、メッセージバッファの他にメールボックスもあります。

リスト2にメールボックスを利用してプログラミングした例を示します※1

※ 以下のサンプルプログラムはこちらからダウンロードできます。

tk_rcv_mbxがメッセージを受信する機能、tk_snd_mbxがメッセージを送信する機能です。

プログラムを動作させるとタスクBの方が先に実行を開始します。タスクBの中の40行目でメッセージを作成し、42行目のtk_snd_mbxで送信しています。メッセージを5回送った段階で起床待ち状態で待ちになり、ここで一旦処理を停止します。その後、タスクAが実行状態となります。タスクAが23行目のtk_rcv_mbxを実行すると、タスクBから送られてきたメッセージを受信することができます。送信されたメッセージが無くなった段階で、26行目でタスクBに起床要求します。タスクBはtk_slp_tskによる停止状態(T-Kernelで言う「待ち状態」)から戻り、再びメッセージを送信し始めます。

メールボックスもメッセージバッファと同様に、予めその準備をしておく必要があります。これが60行目のtk_cre_mbx(メールボックスの生成)です。T-Kernelでは、目的に応じて複数のメールボックスを生成して利用することができます。

メールボックスがメッセージバッファより優れている点は、メッセージバッファ領域を必要としないため、必要最小限のメモリ領域を動的に確保するだけで実装できる点です。メッセージバッファと異なり、メールボックスではメッセージのコピーを行うのではなく、メッセージの先頭アドレスを通知しています。このため、メッセージのサイズが大きい場合は、メールボックスよりも高速に処理できるといった利点があります。ただし、送信した後もそのメッセージを受信側が受信して処理を終えるまでは、メッセージを改変・削除してはいけません。処理が終わる前に、送信メッセージを改変すると、意図しない動作になる可能性があるため、注意が必要です。

通常は、送信側でメモリプール機能※3を利用してメモリ領域を確保し、そこにメッセージを作成してからメールボックスに送信します。受信側では受信したメッセージを使い終わったらメモリプールに返却します。このように実装することで、受信側がメッセージを使い終わる前にメッセージを改変してしまうといった誤りを防ぐことができます。

■メールボックスの生成  tk_cre_mbx (リスト2の60行目)

tk_cre_mbxではメールボックスを生成します。

パラメータにはT_CMBX型の構造体へのポインタを指定します。構造体は以下のように定義されていて、メールボックスに関する情報を設定することができます。

必ず設定しなければならないのは mbxatrだけです。

リスト2では以下の値を変数の宣言時に設定しています(56行目)。

  • mbxatrには、TA_TFIFO|TA_MFIFO を設定しています。
    ここではtk_rcv_mbxでタスクが待ち状態になる場合の並び順と、
    tk_snd_mbxでメッセージが待ち状態になる場合の並び順を設定します。
    TA_TFIFO
    : 待ち状態になる場合の並び順はFIFOにする。
    TA_TPRI
    : 待ち状態になる場合の並び順はタスク優先度順にする。
    TA_MFIFO
    : メッセージの並び順はFIFOにする。
    TA_MPRI
    : メッセージの並び順はメッセージ優先度順にする。

なお、メールボックスの生成に成功すると、tk_cre_mbxの戻値として、生成したメールボックスの識別子(メールボックスID)が返されます※2

■メールボックスへ送信  tk_snd_mbx (リスト2の42行目)

tk_snd_mbxでは、メールボックスへメッセージを送信します。

第1引数には、メールボックスIDを指定します。

第2引数には送信するメッセージパケットの先頭アドレスを指定します。mbxatrに指定する属性により、使用するメッセージの構造体が変わります。TA_MPRIを指定する場合は、T_MSG_PRI型を使用します(それ以外はT_MSG型を使用します)。

図2 メールボックス用メッセージの構造

図2 メールボックス用メッセージの構造

■メールボックスから受信  tk_rcv_mbx (リスト2の23行目)

tk_rcv_mbxでは、メールボックスからメッセージを受信します。

第1引数には、メールボックスIDを指定します。

第2引数には受信するメッセージパケットの先頭アドレスを指定します。

第3引数には、タイムアウト時間を指定します。一定時間待ってもメッセージ受信待ちが解除されない場合、タイムアウトエラーが発生してtk_rcv_mbxが終了します。リスト2では待ち時間(数値)ではなくTMO_POLが指定されています。メッセージが送信されている場合、メッセージを受信し正常終了します。メッセージが送信されていない場合、エラー(E_TMOUT)が返ります。

第3回 タスク間同期・通信機能1> 第5回 タスク間同期・通信機能3


※1 doWorkAやdoWorkBでは、各タスク用の処理を行うものとし、必要に応じて待ちを発生することがあるものとします。各タスクではdoWorkAやdoWorkB以外にもさまざまな処理を行うと思いますが、リストでは簡単にするために省略してあります。

※2 もし、何らかのエラーが発生した場合、戻値は負の値になります。T-Kernelでは、この負の値を「エラーコード」と呼び、エラーの内容をその値で確認することができます。

※3 メモリプール機能に関しては、第8回で説明する予定です。

Return Top