なんでも作っちゃう、かも。

Arduino/Make/フィジカルコンピューティング/電子工作あたりで活動しています。スタバの空きカップを使ったスタバカップアンプなど製作。最近はもっぱらArduinoと3Dプリンタの自作に興味があります。

C言語でコルーチン(co-routine)

Posted by arms22 on 2008年04月07日 0  0

C言語でコルーチンを実装してみる。

コルーチン(co-routine)とはプログラミングの構造の一種。サブルーチンがエントリーからリターンまでを一つの処理単位とするのに対し、コルーチンはいったん処理を中断した後、続きから処理を再開できる。接頭辞co-は協調を意味するが、複数のコルーチンが中断/継続により協調動作を行う。

組み込みシステムではよく、複数の処理を同時に行う必要がある。そのような場合、コルーチンが使えれば、処理の記述が楽に行える。switch-caseあるいは関数テーブルなどを駆使すれば、実現することは可能だが、見通しがわるくなる。

コルーチンをサポートする言語にはModula-2、Simula、Icon、Lua、C#がある。マルチスレッドで原理的には同じことができるため、現在はそちらが使われるケースが多い。

組み込みシステムにおいても上記のことは言えるが、小規模なシステムの場合、リソースの制約上、処理1つ1つにタスクを割り当てることができず、1つのタスクで複数の処理を実行するケースも存在する。

今回、紹介するコルーチンはswitch-caseを巧みに利用して実現されている。次のコードは呼び出すごとに"Hello World"がテキトーになっていくHelloWorld関数だ。
void helloworld(void){
co_begin;

printf("hello world!!\n");
co_yield();

printf("hi world!\n");
co_yield();

printf("hi again.\n");
co_yield();

printf("hi\n");
co_yield();

printf(":)\n");
co_end;
}
main(){
helloworld();
helloworld();
helloworld();
helloworld();
helloworld();
}
実行結果は次の通り。
hello world!!
hi world!
hi again.
hi
:)
見慣れないキーワードが三つ。それぞれ簡単に説明すると、
  • co_begin
    コルーチンの開始
  • co_yield()
    処理の中断
  • co_end
    コルーチンの終了
co_begin,co_endはおまじないと思ってくれ。co_yieldについて説明しよう。
co_yieldは呼び出した時点で処理を中断し関数を抜けるんだ。次にこの関数が呼ばれた時、最後にco_yieldを呼び出したところから処理が再開される。
さて、気になるco_begin,co_yield(),co_endの実装を見てみよう。

#define co_begin              \
static int __state = 0; \
switch(__state){ \
case 0:

#define co_yield() \
do { \
__state = __LINE__; \
return; \
case __LINE__: \
break; \
} while(0);

#define co_end \
__state = __LINE__; \
}
うーん。なかなか良く出来たコードだ。switch-caseを巧みに利用しているのがわかる。もちろんこのマクロは完璧ではない。ローカル変数は使えないし、外部から状態を制御できない。PICなんかだと、1度動作を開始させた後、処理を止める必要がない場合が多いので、今回のマクロで十分かもしれない。

次回は、このコルーチンマクロをもう少し使い易く、ローカル変数を使えるようにしてみる。

コルーチン - Wikipedia
http://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%AB%E3%83%BC%E3%83%81%E3%83%B3

Ads by Google

Leave a reply






管理者にだけ表示を許可する

該当の記事は見つかりませんでした。