スパイス  組み込み制御装置の受注製作

Z80にマルチタスク機能を
平成26年4月30日

 C言語でのコルーチン実装
 C言語上でコルーチンを実装する方法は幾つかあるようです。その中で比較的単純な実装を示します。
#ifndef COROUTINE_H
#define COROUTINE_H

#define CO_VAL_t        int

#define CO_begin(p) {                   \
        CO_VAL_t *co_ptr = p;           \
        switch(*co_ptr) {               \
        case 0:

#define CO_yield(ret)                   \
        do {                            \
                *co_ptr = __LINE__;     \
                return ret;             \
        case __LINE__:;                 \
        } while(0)

#define CO_end()                        \
                ;}                      \
        *co_ptr = 0;                    \
        }

#define CO_reset(co_ptr)                *co_ptr = 0

#endif //COROUTINE_H
 C言語のマクロ機能を利用した実装です。特に処理の中断位置を記憶するために組み込みマクロ機能__LINE__を巧妙に利用しています。
この実装では
  ・コルーチンを実装した関数を識別しやすくするために関数の引数として渡されるコルーチン用の変数に型CO_VAL_tを定義
  ・コルーチンの初期化を明確化するためにCO_reset()マクロを定義
しています。
 これだけで複数の処理をマルチタスクで処理できるのですから、そのメリットは絶大です。

 CO_yield()にはvoid関数用を別に作る必要があるかもしれません。
PIC18用のXC8コンパイラではvoid型の関数に上記のCO_yield()を使用すると”引数が無い”とワーニングになります。確かにあまりお行儀は良くないので、別に分けた方がいいかもしれません。
#define CO_yield_void()                 \
        do {                            \
                *co_ptr = __LINE__;     \
                return;                 \
        case __LINE__:;                 \
        } while(0)

 タスクコンテキストの切り替えによる実装との比較では、下記が異なります。
  ・実装は完全にソフトウェアのみで行われているので、タイマのようなハードウェアを必要としません。
  ・各タスクはタスクの切り替えポイント(CO_yield())に達するまでタスクを切り替え出来ません。
   これは並行処理中のタスクの中のどれか一つでも無限ループに落ち込んだだけで全ての処理が停止します。
   (これは必ずしもデメリットとは限らないので注意が必要です。状況によってはこの方が望ましいこともあります)

目次へ 前へ 次へ