モダンOSのお砂場(41) Mbed OS6、Queue、いろいろ疑問あるんですが。

Joseph Halfmoon

今回はQueueを使ってみたいと思います。第34回で似たお名前のEventQueueというものを使ってみましたが、全く異なるものです。QueueはスレッドやISR間の通信のための仕組みで、EventQueueはノンプリエンプティブな制御権の移動の仕組みです。「よくある」Queueだと思ってやってみたのだけれど疑問あり。何故?

※実験コードのビルドは、Arm社のWeb開発環境 Mbed Compilerを使わせていただいております。登録すればインストールせずに即使える開発環境です。実機ターゲットは、ST Microelectronics社のNucleo-F401REボード(STM32F401REマイコン搭載。コアは Arm Cortex M4F)です。

Queue

Arm Mbed OS6のQueueは、並行に走っている複数スレッド(Mbed OSではタスクでなくスレッドと呼びますです)間で通信するための仕組みです。Queueの一方の端から入れた情報が、他端から、基本は先入れ先出し方式で取り出すことができます(プライオリティ制御も可能とな。使ってみてないケド。)Mbed OS6には、似た機能のAPIにMail (BOX)という仕組みもあるようです。通信の実体メッセージまで格納することができるMailの仕組みと比べると、Queueは、実体メッセージの置き場所は管理してくれず、ポインタのみの格納です。通常はメモリをアロケートするような仕組みと組わせて使うみたいです(今回は「静的」にやっつけてしまいましたが。)

以下がMbed 公式の Queueに関するドキュメントのページです。

Queue

※疑問があるのよ。

キューにデータを出し入れするコードを書くのにドキュメントを読み、以下のように認識しました。

  • exampleコードでは、put() / get() を使っている
  • しかしAPIドキュメントを見ると put() / get() 以外に try_put() / try_get() などのtry_からはじまるメソッド群がある。こちらの方が使い易そうに見える。
  • また、以下のヘッダファイルの定義をみると put() / get() は推奨されていない印象を受ける。try_系を使う方が良いように思える。

Queue.h

上記のヘッダファイルから1箇所引用させていただくと、以下のようです。

MBED_DEPRECATED_SINCE(“mbed-os-6.0.0”, “Replaced with try_put and try_put_for. In future put will be an untimed blocking call.”)

しかし、try_put()使ってみたら、そんなメソッド知らない、と言われてしまいました。エラー。Mbed OSのリビジョンを確認してみましたが、現行の最新版である筈のv6.15でした。何故にtry_チョメチョメが使えない?未だに不明です。

しかたないので、以下のコードは、旧式?の put() / get() で書いてます。

実験用のコード

実験は以下のようです。

  • タスク1は、疑似乱数で10から2550までの10の倍数を生成する。QUEUEを調べてフルでなければ、生成した数をQUEUEにput()する。put()した数字は標準出力に報告する。QUEUEにput出来ても出来なくても生成した数字ミリ秒だけ待つ。ランダムな間隔でputとその表示が起こる。
  • タスク2は、毎10ミリ秒毎にQUEUEをチェックし、QUEUEが空でなければQUEUEからデータを取り出す。getした数字を標準出力に報告する。
  • main()関数は、上記2つのタスクを起動後、無関係にLチカしつづける。
#include "mbed.h"
#include "platform/mbed_thread.h"
#include "stdlib.h"

#define BLINKING_RATE_MS        (500)
#define QUEUE_DEPTH             (8)

Queue<int, QUEUE_DEPTH> qu;
int dataBuffer[QUEUE_DEPTH];
int dataIdx;

Thread t1;
Thread t2;

void t1_thread()
{ 
    int waitMS; 
    while (true) {
        waitMS = (rand() & 0xFF) * 10;
        dataBuffer[dataIdx] = waitMS;
        if (!qu.full()) {
            qu.put(&(dataBuffer[dataIdx]));
            printf("Put: %d\r\n",dataBuffer[dataIdx]);
        }
        dataIdx = dataIdx < (QUEUE_DEPTH - 1) ? dataIdx + 1 : 0; 
        ThisThread::sleep_for(waitMS);
    }   
}

void t2_thread()
{ 
    while (true) {
        if (!qu.empty()) {
            osEvent evt = qu.get();
            int *mess = (int *)evt.value.p;
            printf("Get: %d\r\n",*mess);
        }
        ThisThread::sleep_for(10);
    }   
}

int main()
{
    printf("\r\n\r\n*** Queue Sample ***\r\n");

    dataIdx = 0;
    DigitalOut led(LED1);
    t1.start(t1_thread);
    t2.start(t2_thread);

    while (true) {
        led = !led;
        thread_sleep_for(BLINKING_RATE_MS);
    }
}
ビルド結果

上記コードのMbed Compilerによるビルド結果は以下のようです。

BuildResult

 

ここでも、ちょっとムムムな感じ。

第39回第40回と、Mbed OS6のオブジェクトを生成してますが、それらの回では「あまっているRAMはだいたい」ZI Dataで埋まっているように見えてました。しかし、今回はそういう感じはないです。こちらの方が普通な感じではあるのだけれど、使うAPIによってメモリの使い方が大きく異なる理由が知りたい!

ま、ビルドそのものは成功し、オブジェクトが得られたので、Nucleo-F401REに書き込んで動かしてみます。

実機動作結果

冒頭のアイキャッチ画像に、Nucleo-F401REの標準出力に接続した仮想端末の様子を掲げました。乱数で生成されたと思われる10ms単位の数字をPut して Get して期待どおりの挙動であります。

しかし、なんだかな~ 釈然としないのう。

モダンOSのお砂場(40) Mbed OS6、EventFlags、便利なお知らせ へ戻る

モダンOSのお砂場(42) Mbed OS6、Mail、allocちょっと気が咎めるけど便利 へ進む