LoginSignup
5
8

More than 1 year has passed since last update.

ESP32でマルチスレッド:キューを送る

Last updated at Posted at 2022-01-17

SS 192.png ESP32とArduinoIDEでキューを送りたい

やること

前回の続きで、ESP32DevKitCとArduinoIDEを使って、ESP32でマルチコア・マルチスレッドを使っていきます。

複数のプロセスを並行処理するマルチスレッドでは、プロセス間でデータの受け渡しをする際にルールを決めておかないと、同じデータを同時に上書きするなどの問題が生じます。
そこで今回はキューによるデータの受け渡しを試してみます。

そもそもキューとは

キュー(Queue)とは列のことです。
スレッド間で順次データを送信していくわけですが、キューの仕組みを使えば、もし受け取り先でデータの処理が遅れていた場合に、データを列に並べて待機させることができます。
処理が空き次第、待ち列の先頭からデータを相手にコピーで渡していきます。コピーが済んだ先頭のデータは消去され、次のデータが先頭に押し出されます。


また、今回の説明のようにデータを先入れ先だしする方法のことをFIFO(フィフォ、First In First OUT)と言います。この用語もよく出てきます。

準備

  • Arduino IDEの入ったPC
  • Arduino IDEでESP32が使えるようにしてある
  • ESP32DevKitC

Arduino IDEで試す

ではさっそくキューを試してみましょう

xQueue_test.ino
TaskHandle_t thp[2];//マルチスレッドのタスクハンドル格納用
QueueHandle_t xQueue_1;//Queueを使う準備 [キューハンドル名]

void setup() {
  Serial.begin(115200);

  xQueue_1 = xQueueCreate( 10, 16 );
  //xQueueCreate( [待ち行列の席数], [一席あたりのバイト数] );

  //スレッドの準備
  xTaskCreatePinnedToCore(Core0a, "Core0a", 4096, NULL, 2, &thp[0], 0);
  xTaskCreatePinnedToCore(Core1a, "Core1a", 4096, NULL, 1, &thp[1], 1);
  //xTaskCreatePinnedToCore(
  //   [タスク名], "[タスク名]", 
  //   [スタックメモリサイズ(4096or8192)], [NULL], 
  //   [タスク優先順位(1-24)] 大きいほど優先順位が高い,
  //   [宣言したタスクハンドルのポインタ(&thp[0])], [CoreID(0or1)]); 
}

void loop() {//メインループ
  Serial.println("[ main ] loop");
  delay(100);
}

void Core1a(void *args) {//スレッド ①
  int a = 0;//送信データの変数
  while (1) {
    xQueueSend( xQueue_1, &a, 0 );
    //xQueueSend([キューハンドル名], [送る値], [待ち行列の席が空くまで待つ時間]);
    a++;
    delay(1000);
  }
}

void Core0a(void *args) {//スレッド ②
  int b = 0;//データ受信用の変数
  while (1) {
    /* メッセージ受信待ち */
    xQueueReceive( xQueue_1, &b, portMAX_DELAY );
    //xQueueSend([キューハンドル名], [データを受信するアドレス], [キュー空きを待つ最大時間。portMAX_DELAYで永久待ち])
    Serial.print("[Core0a] xQueueReceive:");
    Serial.println(b);
    delay(1);
  }
}

実行結果


Core0aはdelay(1)間隔の高速ループでキューからの受信を待ち受けています。
一方で、Core1aはdelay(1000)のゆっくりとした間隔でキューを発信しています。
また、メインループはdelay(100)の間隔で更新されています。
このため、メインループ10回の表示につき、Core0aが受け取ったキューを1回表示するという実行結果になります。

ポイント

・キュー先頭のデータは一度取得されると消えます。
 たとえばキューのデータが1つしかない場合に、2つのプロセスからキューのデータを取得しようとすると、最初にキューにアクセスしたプロセスだけがデータを取得できます。
・キューの繰り出しはOSが自動的に行ってくれます。
・キュー空きを待つ最大時間は、portMAX_DELAYで永久待ちとなります。
・送受信用の変数はスレッドの内部に持つようにします。(ローカルスコープ)

参考URL

FreeRTOSでマルチタスク (on ESP32)
Arduino – ESP32 のマルチタスク ( Dual Core ) を試す
[M5Stack] マルチスレッドで並列処理を行う
ESP32のマルチタスクとCPU利用率を調べる
ESP32のFreeRTOS入門 その2 タスクの作成
xQueueReceive
が大変参考になりました。ありがとうございました。

次回

次はセマフォの使い方を試してみます。

次回記事:

前回記事:

5
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
8