超ミニBASICをH8からSHに移植しているときに気付きました。「マルチプロセスやマルチスレッドって意外と簡単じゃないか?」と。
SHは絶対アドレッシングが弱い(というか、無いに等しい)CPUです。H8のようにBASICインタプリタのワークエリアを絶対アドレッシングでアクセスしていては効率悪くてたまりません。そこで、超ミニBASIC for SHではワークエリアの先頭番地をGBRに入れておき、GBR相対アドレッシングでアクセスしています。
H8 |
MOV.B @SKPFLG,R0L |
SH |
MOV.L A_SKPFLG,R13 MOV.B @R13,R0 : A_SKPFLG .DATA.L SKPFLG |
SH |
MOV.B @(SKPFLG-WRKTOP,GBR),R0 |
マルチスレッドができるとどんなことができるかですが、たとえば7セグメントLED複数桁をダイナミック点灯したいとします。この場合、LEDの桁スキャン専用のスレッドを作ってそれにまかせておけば、メインのプログラムは本来の処理に専念できます。従来、そういうことをするにはマシン語でタイマ割り込みなどを使わなければいけなかったのですが、BASICがマルチスレッドになればオールBASICで簡単にできます。
あまり馴染みの無い言葉でしたが、某巨大掲示板のおかげで最近はあちこちで目につきますね。「スレッド(thread)」の本来の意味は「織物の糸」です。コンピュータ用語としてのスレッドは、OS、言語によって微妙に定義が異なりますが、おおむね同一プログラムの中の、1つの連なった処理の流れを意味するようです。
マルチスレッド超ミニBASICでは、「ステムスレッド」と「ブランチスレッド」の2種類のスレッドがあります。「ステム(stem)」は「幹」、「ブランチ(branch)」は「枝」の意味です。一つのプログラムの中に唯1つのステムスレッドと複数のブランチスレッドが存在します。
RUNしたとき最初に走り出す、一番小さい行番号から始まる処理の流れをステムスレッドと呼びます。START文で起動された処理の流れをブランチスレッドと呼びます。
ステムスレッドとブランチスレッドではEND文の働きが異なります。ブランチスレッドでEND文を実行するとそのスレッドが終了するだけですが、ステムスレッドでEND文を実行するとプログラム全体が終了します。木の枝を折りとっても幹は倒れませんが、幹を倒せば枝もすべて倒れる、というのをイメージするとわかりやすいです。
標準版の超ミニBASIC for H8/3048 をほとんどそのままマルチスレッド化しました。スレッドは4つまで同時に走ります。4つって少ないようですが、しょせんBASICインタプリタですからあまり無理をしないほうがよいでしょう。
コンテキストスイッチングは文を1つ実行するごとに行われます。
※PRINT文の使用には注意してください。9600ボーだと1文字表示するのに約1ミリ秒かかります。たとえば1つのPRINT文で100文字くらいの文字列を出力すると、約0.1秒の間コンテキストスイッチングは行われません。
・変数は、全スレッドで共通です。たった26個の変数を4つのスレッドでわけ合うのでけっこうキビシイです。次のバージョンではスレッドごとに変数を独立させるとか、何らかの対策をします。
・メモリ、I/Oなどの排他制御は全くしていません。別のスレッドで同じ番地をアクセスして不具合がおこらないよう、注意してプログラムを組みます。
・実は、INPUT文やGETC関数でキー入力待ちになるとすべてのスレッドが止まります。これも次のバージョンでなんとかしたいところです。
次のプログラムを動かしてみます。
10 FOR I=1 TO 10 20 PRINT "I=",I 30 IF(I=5) START *THRE1 40 NEXT 50 END 100 *THRE1 110 FOR J=1 TO 10 120 PRINT " J=",J 130 NEXT 140 END |
I= 1 I= 2 I= 3 I= 4 I= 5 I= 6 J= 1 I= 7 J= 2 J= 3 I= 8 J= 4 I= 9 J= 5 J= 6 I= 10 J= 7 |
50 WAIT THREADS(0)<2 60 END |
I= 1 I= 2 I= 3 I= 4 I= 5 I= 6 J= 1 I= 7 J= 2 J= 3 I= 8 J= 4 I= 9 J= 5 J= 6 I= 10 J= 7 J= 8 J= 9 J= 10 |
このページではマルチスレッド関連の文・関数のみ説明します。他の、マルチスレッドとは関係ない文・関数については標準版と同じなのでこちらをご覧ください。
書式:
コンテキストスイッチングを許可します。複数のスレッドが走っている場合、各スレッドに順に実行権が行き渡るようになります。
なお、RUN直後はデフォルトでコンテキストスイッチングは「許可」になっています。
ENACS文はダイレクトモードでは実行できません。
書式:
コンテキストスイッチングを禁止します。他のスレッドに割り込まれたくないときに使用します。ENACS文を実行するまで他のスレッドに実行権は移りません。
DISCS文はダイレクトモードでは実行できません。
書式:
ブランチスレッドを起動します。*<ラベル>で指定された行以降がブランチスレッドとして動きます。START文を実行した元スレッドもそのまま実行を続けます。
START文はダイレクトモードでは実行できません。
書式:
<式>の値が0以外になるまで待ちます。コンテキストスイッチが許可になっていれば待っている間も他のスレッドに実行権は行き渡ります。
書式:
現在走っているスレッド数を返します。返る値は1〜4です(ステムスレッドは常に走っているので0が返ることはありえません)
<式>の値は現バージョンでは無意味ですが、0を指定してください。
この関数は、すべてのブランチスレッドが終了したのを確認からステムスレッドを終了したい場合などに使います。
書式:
ステムスレッドで実行するとプログラム全体が終了します。ブランチスレッドで実行するとそのスレッドだけを終了させ、コンテキストスイッチングを許可にします。
OUT OF THREAD SPACE |
すでに4つスレッドが走っているのに、さらにスレッドを起動しようとした |
BAD MODE |
ENACS文、DISCS文、START文をダイレクトモードで実行しようとした |