STM32でNUTTXを使ってみる

Counting Semaphore Interfaces


マルチタスクのシステムを設計する際に、重要な要素として資源の排他制御が有ります。
例えば共有メモリを書き換えるときは、共有メモリを書き換えている最中は、他のタスクが参照できない様に
共有メモリという資源をロックし、書き換えが終わったら資源をアンロックします。
タスク間のメッセージングにファイルを使う場合も同様に排他制御を行います。
そこで、資源の排他制御を行うCounting Semaphore Interfacesを紹介します。

この動作を確認するためのサンプルアプリを公開しています。
こちらの手順でapps/examplesディレクトリに追加してくださ い。
以下の手順でサンプルアプリをファームに組み込みます。
$ make clean
$ make menuconfig

Application Configuration > Examples で以下のアプリを追加してください。


Counting Semaphore InterfacesにはUN-NAMED semaphore と NAMED semaphore が有ります。
NAMED semaphore を使うためには、File systemメニューで以下を追加する必要が有ります。


Named semaphore supportを有効にしたらひたすらExitで抜けます。
最後に以下の画面で[.config]を上書きします。


新しい[.config]を使ってファームウェアをビルドし、新しいファームウェアをマイコンに書き込みます。
nshに接続するとsem_testアプリが追加されています。




startの引数で実行すると、2つのタスクを起動します。
myTask1は[foo] myTask2は[bar]のロックを試みます。
どちらのセマフォも初期値が0なので、ロックできずに待たされます。
nsh> sem_test start
task_create name:myTask1 priorty:100
task_create name:myTask2 priorty:100
myTask1 start PID:7 system_timer:1941
myTask1 Open semaphore[foo]
myTask1 Try Lock semaphore [foo]
myTask2 start PID:9 system_timer:1942
myTask2 Open semaphore[bar]
myTask2 Try Lock semaphore [bar]
nsh> ps
  PID GROUP PRI POLICY   TYPE    NPX STATE    EVENT     SIGMASK   STACK COMMAND
    0     0   0 FIFO     Kthread N-- Ready              00000000 001000 Idle Task
    9     9 100 RR       Task    --- Waiting  Semaphore 00000000 002000 myTask2 bar
    2     2 100 RR       Task    --- Running            00000000 002000 nsh_main
    7     7 100 RR       Task    --- Waiting  Semaphore 00000000 002000 myTask1 foo
nsh>




fooの引数で実行すると、[foo]をアンロック(+1)します。
myTask1のロック(-1)が正常に行われます。
再度ロックを試みますが、セマフォ値が0なので、ロックできずに待たされます。
nsh> sem_test foo
myTask1 Lock success semaphore [foo]
myTask1 Try Lock semaphore [foo]
nsh>



barの引数で実行すると、[bar]をアンロック(+1)します。
myTask2のロック(-1)が正常に行われます。
再度ロックを試みまが、セマフォ値が0なので、ロックできずに待たされます。
nsh> sem_test bar
myTask2 Lock success semaphore [bar]
myTask2 Try Lock semaphore [bar]
nsh>



addの引数で実行すると、myTask3を起動します。
myTask3も[foo]のロックを試みます。
nsh> sem_test add
task_create name:myTask3 priorty:100
myTask3 start PID:14 system_timer:9877
myTask3 Open semaphore[foo]
myTask3 Try Lock semaphore [foo]
nsh> ps
  PID GROUP PRI POLICY   TYPE    NPX STATE    EVENT     SIGMASK   STACK COMMAND
    0     0   0 FIFO     Kthread N-- Ready              00000000 001000 Idle Task
    9     9 100 RR       Task    --- Waiting  Semaphore 00000000 002000 myTask2 bar
    2     2 100 RR       Task    --- Running            00000000 002000 nsh_main
   14    14 100 RR       Task    --- Waiting  Semaphore 00000000 002000 myTask3 foo
    7     7 100 RR       Task    --- Waiting  Semaphore 00000000 002000 myTask1 foo
nsh>

これに続けてfooの引数で実行すると、myTask1 myTask3の順番にロックが行われます。
nsh> sem_test foo
myTask1 Lock success semaphore [foo]
myTask1 Try Lock semaphore [foo]
nsh> sem_test foo
myTask3 Lock success semaphore [foo]
myTask3 Try Lock semaphore [foo]
nsh> sem_test foo
myTask1 Lock success semaphore [foo]
myTask1 Try Lock semaphore [foo]
nsh>



通常、セマフォの初期値は同時に資源にアクセスできるタスク(スレッド)の数を指定します。
資源を使う前にsem_waitで資源のロックを試みます。
セマフォ値が1以上の時は資源にアクセスできますが、0以下になると資源をロックすることができずに待たされます。
資源をロックすることができずに待たされた場合、実行権はほかのタスクに移ります。
資源を使った後には、sem_postで資源をアンロックします。
タスク1(優先度=100)

セマフォ値

タスク2(優先度=200)
タスク起動

1


資源のロック(sem_wait)
---->
1


ロック成功
<----
0

タスク起動


0
<----
資源のロック(sem_wait)
資源の利用

0

待たされる
資源の利用
0

待たされる
資源のアンロック(sem_post) ----> 1

待たされる
実行権の放棄

0
---->
ロック成功


0

資源の利用


0

資源の利用


1
<----
資源のアンロック(sem_post)

なお、スケジュールポリシーがFIFOで、システム内の全てのタスクの優先度が同じ場合は、
タスクが実行権を放棄しない限り、他のタスクは動けないので、セマフォーによる資源の排他制御は不要になります。
タスク1(優先度=100)

セマフォ値

タスク2(優先度=100)
タスク起動

1


資源のロック(sem_wait)
---->
1


ロック成功
<----
0

タスク起動
資源の利用

0

FIFOなので動けない
資源の利用

0

FIFOなので動けない
資源のアンロック(sem_post)
---->
1

FIFOなので動けない
実行権の放棄

1

FIFOなので動けない


1
<----
資源のロック(sem_wait)


0
---->
ロック成功


0

資源の利用


1
<----
資源のアンロック(sem_post)

以下はセマフォの初期値を2にした時の例です。
2回までは資源をロック(=使う)ことができますが、3回目は資源が枯渇するのでロックに失敗します。
nsh> sem_test test
BEFORE sem value=2
sem_timedwait status=0 ---> ロック成功
AFTER sem value=1
BEFORE sem value=1
sem_timedwait status=0 ---> ロック成功
AFTER sem value=0
BEFORE sem value=0
sem_timedwait status=-1 ---> ロック失敗
AFTER sem value=0
nsh>



APIの使い方に間違いがあるかもしれません。
こ ちらのドキュメントで確認してください。

ファームの書き込み方法と、nshへの接続方法はこちらに紹介しています。
STM32F4 Discovery
STM32F3 Discovery
STM32F103RB Nucleo
STM32F103 BluePill/BlackPill
STM32F103 VEボード
STM32F407 VGボード

続く...