内蔵モジュールなどのリソースを複数タスクで使う場合、競合が起きても
いずれかの使用が完了するまで待たせるようにするための機能が
排他制御(MUTEX)です。
【排他制御の説明】
排他制御は、下図のようにタスク1とタスク2の2つがUARTなどのリソースを
使って出力する場合、UARTの出力などには時間がかかるため、タスク1が
出力中にタスク2の出力要求が発生して競合する場合があります。
このように競合する場合、タスク1がUARTを使用する前に、MUTEXのセマフォを
Takeしてビジーにしておき、使用が完了したらMUTEXをGiveしてレディにするように
します。
これで、タスク2は同じMUTEXがビジー中はTakeできないため、レディーになるまで
待たされ、タスク1が終わってから使うということになります。
このようにして競合が起きても先発優先で交通整理して重ならないようにするのが
排他制御です。
【排他制御の使用例】
実際の使用例です。上記の説明と同じ機能で、タスク1とタスク2からUARTに
メッセージを出力する構成です。
宣言部とmain関数部は下記リストとなります。ここでMUTEXを生成し、これが
正常に生成できたらタスクを生成して動作開始しています。
次に各タスク関数は下記リストのように作成しています。タスク1とタスク2の
2つのタスクで、UARTに出力するprintf文の前後でMUTEXをTakeしGiveする
ようにしています。
このプログラムでの実際の出力は、下記のように順番どおりに
きれいに出力されます。
これに対し、MUTEXのTakeとGiveの文をコメントアウトして挿入しない
ようにした場合には、下記のような出力結果となります。
タスク1の出力途中でもう一方のタスク2の出力が重なるとき、出力内容が
乱れることが判ります。
★★★ MUTEXの使用例のプログラムダウンロード(sample6)
【排他制御の問題と代替の構成方法】
排他制御を使う場合いくつかの問題があります。
★各タスクの中で待ち合わせが発生し、タスクの実行遅れが予測できない
★場合によると複数タスクが互いに待ち状態となり先に進まなくなるデッド
ロックが起きうる
このような問題があるため、MUTEXは余り使われず、代替の方法として
内蔵モジュールを使うタスクを1つのタスクに限定し、キューを使って入出力要求
をするようにします。
例えば上記の例題をキューを使った構成に変更すると、下記のようになります。
キューの使用例で作成した基本的な例題と同じ構成となります。
まずメイン関数部が下記リストとなります。
キューの生成をしたあと、生成が成功したらタスクを生成してスケジュールを
開始しています。
ここではUARTにメッセージを直接送信しているためデータサイズが大きく、
タスクのスタックサイズを大きめにしないと不足しますので200としています。
次に各タスク関数部です。標準的な手順どおり、タスク1とタスク2から
キューにSendし、タスク3でReceiveで取り出してprintf文で出力しています。
メッセージを直接送っていますので、キューが大きめのサイズとなっています。
★★★ キューによる制御のプログラムダウンロード(sample7)
目次に戻る