からくりブログ

株式会社からくり社員のブログです

Raspberry Pi 3 + μITRON その7(セマフォその2)

前回はセマフォについて説明しました。今回はRaspberry Pi3での動きを見ながらセマフォについておさらいしたいと思います。 セマフォを増やしたり減らしたりについては、前々回同様「コンフィギュレータ」を使用してリソースをいくつ使用するかを定義します。
前々回のasp3/sample/sample1.cfgをもう一度掲載しておきます。

/*
サンプルプログラム(1)のシステムコンフィギュレーションファイル
*
$Id: sample1.cfg 705 2016-03-29 14:16:41Z ertl-hiro $
*/
INCLUDE("tecsgen.cfg");
include "sample1.h"
CRE_TSK(TASK1, { TA_NULL, 1, task, MID_PRIORITY, STACK_SIZE, NULL });
CRE_TSK(TASK2, { TA_NULL, 2, task, MID_PRIORITY, STACK_SIZE, NULL });
CRE_TSK(TASK3, { TA_NULL, 3, task, MID_PRIORITY, STACK_SIZE, NULL });
CRE_TSK(MAIN_TASK, { TA_ACT, 0, main_task, MAIN_PRIORITY, STACK_SIZE, NULL });
CRE_TSK(EXC_TASK, { TA_NULL, 0, exc_task, EXC_PRIORITY, STACK_SIZE, NULL });
CRE_CYC(CYCHDR1, { TA_NULL, { TNFY_HANDLER, 0, cyclic_handler }, 2000000, 0 });
CRE_ALM(ALMHDR1, { TA_NULL, { TNFY_HANDLER, 0, alarm_handler }});
CRE_FLG(FLG1, {TA_CLR | TA_WMUL, 0});
ifdef INTNO1
CFG_INT(INTNO1, { INTNO1_INTATR, INTNO1_INTPRI });
CRE_ISR(INTNO1_ISR, { TA_NULL, 0, INTNO1, intno1_isr, 1 });
endif /* INTNO1 */
ifdef CPUEXC1
DEF_EXC(CPUEXC1, { TA_NULL, cpuexc_handler });
endif /* CPUEXC1 */

今回はここにセマフォを追加します。具体的には、前回簡単に説明した「CRE_SEM」を追加します。場所は前回追加した「CRE_FLG」の下に追加します。
追加した結果は以下の通りとなります。

/*
サンプルプログラム(1)のシステムコンフィギュレーションファイル
*
$Id: sample1.cfg 705 2016-03-29 14:16:41Z ertl-hiro $
*/
INCLUDE("tecsgen.cfg");
include "sample1.h"
CRE_TSK(TASK1, { TA_NULL, 1, task, MID_PRIORITY, STACK_SIZE, NULL });
CRE_TSK(TASK2, { TA_NULL, 2, task, MID_PRIORITY, STACK_SIZE, NULL });
CRE_TSK(TASK3, { TA_NULL, 3, task, MID_PRIORITY, STACK_SIZE, NULL });
CRE_TSK(MAIN_TASK, { TA_ACT, 0, main_task, MAIN_PRIORITY, STACK_SIZE, NULL });
CRE_TSK(EXC_TASK, { TA_NULL, 0, exc_task, EXC_PRIORITY, STACK_SIZE, NULL });
CRE_CYC(CYCHDR1, { TA_NULL, { TNFY_HANDLER, 0, cyclic_handler }, 2000000, 0 });
CRE_ALM(ALMHDR1, { TA_NULL, { TNFY_HANDLER, 0, alarm_handler }});
CRE_FLG(FLG1, {TA_CLR | TA_WMUL, 0});
CRE_SEM(SEM1, {TA_TFIFO, 0, 1});     // ★
#ifdef INTNO1
CFG_INT(INTNO1, { INTNO1_INTATR, INTNO1_INTPRI });
CRE_ISR(INTNO1_ISR, { TA_NULL, 0, INTNO1, intno1_isr, 1 });
endif /* INTNO1 */
ifdef CPUEXC1
DEF_EXC(CPUEXC1, { TA_NULL, cpuexc_handler });
endif /* CPUEXC1 */


この状態でビルドしたところ、なぜか「TA_TFIFO」が見つからないとエラーになりました。
検索したところ、TA_TFIFOはitron.hに定義されています。
このsample1.cfgはsample1.hをincludeしているので、sample1.hにitron.hをincludeするようにしました。

/*
サンプルプログラム(1)のヘッダファイル
*/
#include <kernel.h>
#include <itron.h>

さて、実際に動作確認するプログラムの修正です。

ER ercd;
// FLGPTN p_flgptn;
while (true) {
   syslog(LOG_NOTICE, "task%d is running (%03d). %s", 
                                          tskno, ++n, graph[tskno-1]);
   //for (i = 0; i < task_loop; i++);
    // ercd = wai_flg(FLG1, tskno, TWF_ANDW, &p_flgptn);    // ★
    ercd = wai_sem(SEM1);                                   // ★
    c = message[tskno-1];
    message[tskno-1] = 0;
   switch (c) {
    case 'e':
        syslog(LOG_INFO, "#%d#ext_tsk()", tskno);
        ercd = sig_sem(SEM1);                          // ★
        SVC_PERROR(ext_tsk());
        assert(0);
*
*  メインタスク
*/
void main_task(intptr_t exinf)
{
:
#endif /* TASK_LOOP */
    HRTCNT  hrtcnt1, hrtcnt2;
 //   ER      flg_ercd;                         // ★
   ER sem_ercd;                             // ★
:
    /*
      *  メインループ
     */
    do {
        SVC_PERROR(serial_rea_dat(TASK_PORTID, &c, 1));
        switch (c) {
        case 'e':
        case 's':
        case 'S':
        case 'd':
        case 'y':
        case 'Y':
        case 'z':
        case 'Z':
            message[tskno-1] = c;
//            flg_ercd = set_flg(FLG1, tskno);  // ★
              sem_ercd = sig_sem(SEM1);         // ★
            break;
:

★印のところが変更箇所です。
wai_sem()でセマフォを取得し、sig_sem()で返却します。
1番から順にタスクを指定して終了させると次のタスクが動き出し、また終了させると次のタスクが動き出す、というふうにしてあります。
これを動かした結果は以下のとおりです。

h4用汲愁喉有J?х頻濠R4
4壼ヘム雰|ス撈・ケ掾「・ュ゛ヘ★ム・ム舞ケjR4ォ
ォ.ョ・Wャ
メW,.].HJYシZキウ = 0).
task1 is running (001).
task2 is running (001).
task3 is running (001).

いつものように文字化けしていますが…、それぞれのタスクがwai_sem()で起床待ちとなっています。何故かログが「task」しか出なくなり、2時間くらいハマりました…。結局いろいろいじくったらまた出るようになったんですけどね…。原因不明です。
ここで1番のタスクを終了するために「1」と「e」を入力します。すると次のようになります。

4壼ヘム雰|ス撈・ケ掾「・ュ゛ヘ★ム・ム舞ケjR4ォ
ォ.ョ・Wャ
メW,.].HJYシZキウ = 0).
task1 is running (001).
task2 is running (001).
task3 is running (001).
xt_tsk()
task2 is running (002).

また盛大に文字化けしていますが、task1がext_tsk()で終了し、sig_sem()でセマフォを返却したのでtask2が動き出しました。ここでtask2を終了すると次の様になります。

4壼ヘム雰|ス撈・ケ掾「・ュ゛ヘ★ム・ム舞ケjR4ォ
ォ.ョ・Wャ
メW,.].HJYシZキウ = 0).
task1 is running (001).
task2 is running (001).
task3 is running (001).
xt_tsk()
task2 is running (002).
task3 is running (002).

task2のext_tsk()が出ませんでしたが、タイミングの問題です。
task3を終了させるとまとめて出てきます。
このようにして、セマフォの動作を確認することができました。
今回もサンプルプログラムを最小限の改造で動かすようにしたので、イマイチ使い方にピンと来なかったかもしれませんが、前回も書いたとおり、排他的にアクセスしないといけない資源にアクセスし、終わったら他のタスクにアクセス権を明け渡すという使い方です。
今回は一つのセマフォを使いましたが、排他制御したいものが複数ある場合、それに合わせて複数のセマフォを定義してアクセスを管理することも可能です。
サンプルでは「SEM1」などという適当な名前をつけましたが、実際の開発では具体的に何なのかすぐに分かる名前をつけて管理しましょう。それではまた。

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>