はじめに
uITRON(FreeRTOSベース)Windowsシミュレータ - Qiita
https://qiita.com/imagou/items/42c687402e6e58fccddb
今回のお題は、排他の仕組みであるミューテックスです。
本編
1. 環境
こちらの記事を参照ください。
2. 動かしてみる
2-1. (おさらい)受信タスクにメッセージを飛ばす
コンソールで「10」と入力してみましょう(入力後にEnterを押してください)。
[TimerTask]: DELAY 3000ms
[TimerTask]: DELAY 3000ms
10
[SendTask]: RECV EVENT (00000400)
[RecvTask]: RECV MESSAGE (10,1)
RecvTask
が「10」を受信していることがわかるかと思います(2つ目の「1」は受信回数です)。
2-2. 受信タスクのロック~メッセージ送信
次に、コンソールで「lock」と入力してみましょう。
[TimerTask]: DELAY 3000ms
[TimerTask]: DELAY 3000ms
lock
[SendTask]: RECV EVENT (00800000)
特にコンソールには出てきませんが、この時点で受信タスクはロックしています。
※ただしTimerTask
まで止まってしまうのが謎なので、追って調査します・・・
(2019/11/22) 解決させました。
その後、「11」「12」を入力してみます。
11
[SendTask]: RECV EVENT (00000800)
12
[SendTask]: RECV EVENT (00001000)
受信タスクがロックしているため、RecvTask
うんぬんのログが出ません。
2-3. 受信タスクのアンロック
「unlock」を入力し、受信タスクをアンロックしてやります。
unlock
[RecvTask]: RECV MESSAGE (11,3)
[RecvTask]: RECV MESSAGE (12,4)
[TimerTask]: DELAY 3000ms
[TimerTask]: DELAY 3000ms
解放されたRecvTask
が、「11」「12」を順に受信していることがわかるかと思います。
3. 解説
3-1. 概要
ミューテックスは、RTOSに限らずよく利用されている、排他の仕組みです。
主たる利用方法は、**「共通のリソースを複数のタスクで触りたい」**場合かと思います。
(今回の例はあくまで動作確認用のため、タスクの停止・再開用途ですが、実用的ではないかと・・・)
3-2. コードによる説明
以降は、プログラムコード - main.c
を引用して説明します。
3-2-1. ミューテックス生成
cre_mtx()
で生成します。
T_CMTX cmtx;
cmtx.mtxatr = TA_TFIFO;
cre_mtx(MTX_ID(RECV), &cmtx);
このパラメータは下表:
パラメータ番号 | 名称 | 説明 |
---|---|---|
第1パラメータ | ミューテックスID | 単なるID。 以降はこのIDでもってロック・アンロックを実施。 |
第2パラメータ | T_CMTX構造体変数 | 下表で説明。 |
T_CMTXのメンバは下表:
名称 | 指定可能な値 | 説明 |
---|---|---|
mtxatr | TA_TFIFO | TA_TPRI | ミューテックス属性。 それぞれ、待ちキューの順序をFIFO順とするか、優先度順とするか。 |
※なお、mtxatrはこれ以外の値も指定可能(だが、上記のみで必要十分と考える)。
3-2-2. ミューテックスのロック
loc_mtx()
を使います(以下は受信タスクのコード)。
資源がロックされていればアンロックまで待ちますし、そうでなければ即抜けます。
/* Lock/Unlock Mutex */
loc_mtx(MTX_ID(RECV));
unl_mtx(MTX_ID(RECV));
以下(コマンドタスク)ではploc_mtx()
を使っています。
p
はポーリングを意味し、こちらは待ちに入りません。
すなわち、資源がロックされていれば即エラーE_TMOUT
を返し、そうでなければ即E_OK
を返します。
(コメントの通り、コマンドタスクでの多重ロックを避けるために使用しています)
/* Lock */
else if (EQUALS_(lock)) {
/* 多重ロックを避けるためポーリングとする。 */
if (ploc_mtx(MTX_ID(RECV)) == E_OK) {
/* ダミーメッセージを投げ、ロック待ちに遷移させる。 */
set_flg(FLAG_ID(SEND), EVENT_DUMMY);
}
}
3-2-3. ミューテックスのアンロック
unl_mtx()
を使います。
資源がロックされていたらアンロック(解放)します。この関数は待ちません。
ざっくり書くと
コマンドタスクのアンロックにより、受信タスクのロックが解除されて動き出す
というカラクリです。
/* Unlock */
else if (EQUALS_(unlock)) {
unl_mtx(MTX_ID(RECV));
}
おわりに
複数の資源を扱えるセマフォという輩もいますが、概ねミューテックスで事足りると思います。
根本的には、排他不要な設計がベストと思いますが、どうしようもない場合(笑)に利用ください!
参考
Micro-ITRON4.0 Specification (in Japanese)
http://www.ertl.jp/ITRON/SPEC/mitron4-j.html