ABCL/f システムにおいて,マルチスレッディングは StackThreads によって実現されており, 各プロセッサはスレッド各々に対してスタックを持つのではなく, 単一のスタック上で複数スレッドが停止/再開されながら実行されている. 我々の方式では各プロセッサ上で gdb を立ち上げ, 単一スタック上に各スレッドに対応するスタックが積み重なって実行されている 様子を眺めることになる.
ABCL/f では,各 スレッド は,その計算が途中でブロック しない限りにおいて,Cの手続き呼び出しを用いて, 単純にスタックを積み上げながら計算を続ける事になる. このため, マルチスレッド に関連する部分以外においては, 挙動が C/C++ の場合と全く同じであるため, gdb を用いてスレッドを自然にトレースする事が出来る.
一方, future, touch, reply, remote future, remote reply, method invoke といった, マルチスレッド に関する箇所に関しては, StackThreads のスケジューリングにそった形で スレッド 実行を追う事になる.以下各々の場合について説明していく.
まずは,future, touch, replyについて, gdb 上での扱いと,内部でのスタック実行の様子を解説する.
これは, StackThreads上での以下のような実行の様子に対応している. futureによってあらたなスレッド fをforkする場合, 内部では f が caller に優先してスケジューリングされており, fは単なる手続き呼び出しとして呼び出される. つまり, スタック上では caller の上にfの実行フレームが積み重ねられる形で 実行が進行する. その上で, fの実行過程でブロックが起こった場合は,fの実行過程で つまれたフレームが巻戻され,callerのフレームまでもどることになる. つまり, gdbでstep実行を行った場合,そのfの実行をトレース することになり,next実行の場合そのトレースをスキップすることに なるわけである.
これは, StackThreads上で,スレッドがブロックした場合, その後,そのフレームはヒープに移動し, スタックがcaller側まで巻戻されることに対応している. 実行は,caller側で再開される事になる. 一方,ヒープ上に退避されたフレームは,channelへの値のreply があった時点で再開されるべく,保存されている.
一方,すでにtouch 命令 によりreply channelへの値待ちを おこなっているスレッド fがある場合, システムは touchを行ったスレッド g に優先して fの実行を行う. step実行を行った場合,fの実行の様子をトレースすることができる. そして,fの実行が終了,もしくは途中でブロックした場合, touchをおこなった側のスレッド g に実行トレースが復帰する事となる. touch 命令をnext実行したばあい,スレッド fのトレースは スキップされ,スレッド g 上の実行トレースを継続することとなる.
これは,ABCL/f では channelでreply待ちになっているスレッド fがある場合, reply 命令が行われた時点で, ヒープ上に退避されていたfのフレームを現在のスタックの上に積み, その再開を行うからである. このため,step命令は f の実行の様子をトレースに対応し, next実行では,fの実行トレースはスキップする事になる.
また,ABCL/f は並列/分散環境で複数プロセッサを用いて プログラムを並列実行することができるが, remote future や remote reply の際の 内部で起こっている挙動と gdb の対応は以下の通りである.
いずれの場合も,future, replyの時点で実行すべきことはほとんどない. 今回のデバッガの実装では, gdb は以下のような挙動をすべく 設定されている.
これは,呼び出し側ノードでは, 手続き内部では remote future を行うためのメッセージ作成ならびに 送信のみがおこなわれているのにそのまま対応している.
実際に対応するoperationを実行する側では, 伝えられた実行コンテクストを立ち上げることになる. つまり,今回実装を行っている分散メモリ並列環境においては ポーリングしたメッセージの実行内容をスケジューリングを行い, 共有メモリ並列環境においては,キューなどを介して伝えられた 実行コンテクストを取り出しスケジューリングを行う事になる.
StackThreads においては,任意の時点で新たな スレッド をスケジューリングすることが出来, 実際,ABCL/f の分散メモリ環境における実装では, 適当な箇所にメッセージのポーリングならびにスケジューリング を行うコードが埋め込まれており, スレッドの実行中に割り込むような形で他のノードからの実行要求 が処理することができる. 加えて,プロセッサがするべき仕事がない場合は, 他のノードからの実行要求を待ち続ける事になる.
gdb 上においては,他のノードからの実行要求は 他のスレッド実行中に割り込んで来る形,もしくは, 他のノードからの要求待ちの状況で実行される. この時点でデバッガから実行のトレース方法について聞かれるため, step 実行を行うと答えれば実行のトレースを, next 実行を行うと答えればトレースのスキップを行う事が出来る. 具体的に,future, replyの場合について以下のようにデバッガは振る舞う.
最後に,並列オブジェクトの振舞について触れる.
ABCL/f の並列オブジェクトは defmethod! で定義されたメソッドに関して, single threadness が保証されている. このため, あるメソッド実行中に起動された他のメソッドは即座には実行できず, 一度キューに入れられ,実行中メソッドの終了後立ち上げられる事になる.
gdb 側では,そのような場合,メソッド実行の始めの行でブロック することになる.逆に,現在実行中のメソッドが終了する箇所で, キューに入っていたメソッド実行が再開される. これも,step実行を行う事によりその再開実行をトレースする事が出来, 一方,next実行でトレースをスキップすることができる.