提供: Japanese Scratch-Wiki
スレッド(英: thread)は、Scratchのプログラムを実行する際の最小単位で、多くの場合1スクリプトが1スレッドに対応する。シーケンサー(英: sequencer)は、スレッドの動作を制御する。
Scratchのプログラムは、実際には同時実行しない。以下の順位で実行される:
- スプライト(クローン含む)間は、レイヤーが一番上のスプライトが最初に実行され、ステージが最後に実行される。
- 同スプライトのスクリプト間では、最初に追加されたハットブロックが最初に実行され、最後に追加されたハットブロックが最後に実行される。
スレッド
スレッドは、各スクリプトを表現している。ただし、定義ブロックは、呼び出し元のスレッドによる実行となり、定義ブロック用のスレッドによって行われるわけではない。スレッドには以下の状態がある:
定数 | 値 | 説明 |
---|---|---|
STATUS_RUNNING | 0 | スレッドは実行中。 |
STATUS_PROMISE_WAIT | 1 | スレッドは非同期で実行されていて、実行完了を待っている。 |
STATUS_YIELD | 2 | スレッドの次の実行まで待つ。 |
STATUS_YIELD_TICK | 3 | 次のフレームまで待つ。 |
STATUS_DONE | 4 | スレッドは実行を終了した。 |
フレーム
Scratchは、1秒間に30回描画する。(フレーム)そして、シーケンサーは、以下の条件をすべて満たす限り、1フレーム内で可能な限り多くのスレッドを実行する:
- 実行時間は、1フレームの75%未満(25ミリ秒程度)
- STATUS_DONEではないスレッドが存在する。
- フレーム内の2回目以降の実行では、STATUS_RUNNINGであるスレッドが存在する。
- ターボモードであるか、またはステージの再描画が要求されていない。
1フレーム内の動作順序は次の通り:
- 強制的に終了させられたスレッドを当該フレームの実行対象から外す。
- 条件駆動のハットブロックを実行させる。
- ステージモニターの値の更新を予約する。
- タイマーを更新する。
- スレッドの実行。(ステージモニターの値の計算を含む)
- 実行が終了したスレッドを次のフレームの実行対象から外す。
- スクリプトのハイライトを更新する。
- 緑の旗のハイライトを更新する。
- ステージを描画する。
- スプライト情報を更新する。
- ステージモニターを更新する。
スタックとスタックフレーム
スレッドは、スタックの集まりである。1つのスタックは、1つのスタックブロックや、それに接続できるブロック(C型ブロックやハットブロック、キャップブロックなど)を表している。それぞれのスタックには、「スタックフレーム」というものがあり、そのスタックに関する情報を保管する。たとえば、() 回繰り返すブロックは、残りの繰り返し回数をスタックフレームに保管している。
スタックは、前のブロックの実行後に動的に追加される。このため、前のブロックの実行中にブロックを後ろにつなげても、つなげたブロックが実行される。C型ブロックの場合は、条件を満たした場合は中にあるブロックを次のスタックとして追加する。
スレッドの実行
スレッドの実行は以下の通りに行われる:
- スレッドにスタックがもうない場合は、実行を終了して次のスレッドに移る。
- スレッドがSTATUS_YIELD_TICKであり、かつこのフレームでスレッドがまだ実行されていない場合は、スレッドの状態をSTATUS_RUNNINGにする。(つまり、STATUS_YIELD_TICKはフレームの最初でのみ実行される。)
- STATUS_RUNNINGまたはSTATUS_YIELDのスレッドに対しては:
- スタックを取得する。もしそれがnullの場合(例: 空のCブロック)は、次のスタックに進み、それでもスタックがない場合(ハットブロック単独の場合など)はスレッドを止める。
- スタックを可能な限り実行する:
- 「再描画せずに実行」モードの場合は、500ミリ秒のタイマーを設定する。この場合、ブロックが500ミリ秒以内に実行し終わった時は、STATUS_YIELDの場合も実行を続ける。
- スレッドの実行元のスプライトが削除された場合は、実行を終了する。
- それ以外の場合は、そのスタックを実行する。
- スレッドがSTATUS_YIELDの場合は、他のスレッドに処理を移す。(ただし、「再描画せずに実行」モードで前述のタイマーが時間切れでない場合を除く。)
- スレッドがSTATUS_PROMISE_WAITの場合は、非同期実行されたブロックが実行し終わるまでなにもできないので、他のスレッドに処理を移す。
- スレッドがSTATUS_YIELD_TICKの場合は、次の処理はフレームの最初まで待たないといけないので、他のスレッドに処理を移す。
- 実行中のスタックが変化していない場合(C型ブロックの分岐にはまっていない場合)は、次のブロックに進む。
- 次のスタックがない場合(C型ブロックの内部の終わりなど)は、スタックが見つかるまで以下を繰り返す:
- スタックを取得する。
- スタックがもうない場合は、STATUS_DONEにして終了する。
- 取得したスタックがループするC型ブロックの場合は、他のスレッドに処理を移す。(ただし、「再描画せずに実行」モードで前述のタイマーが時間切れでない場合を除く。)ループのブロックが次に実行されたときに、条件を再チェックしどのブロックに進むか決める。
- 次のブロックに進む。
スタックの実行
スタックを実行するときは、まず引数の値ブロック等を処理し、最後に一番下のブロック(ほとんどの場合スタックブロック)を実行する。
- キャッシュを取得する。このキャッシュには、実行しようとしているブロックの引数などの情報が含まれる。キャッシュがない場合(=ブロックが削除された場合)は終了する。
- もし引数に実行された値ブロックがある場合は、
- 前回実行時の返り値を引数として使う。
- 最後に実行され、かつまだ削除されていないブロックを探す。ブロックが実行中の間に削除された場合は、これによって次に実行するブロックを決める。
- 返ってきた値がある場合は、引数として使う。
- スタック内のブロックを実行する:
返り値の処理
- 返り値をスレッドの返り値リストに追加する。
- ハットブロックの場合は:
- 条件駆動のハットブロックの場合は、クリックによって実行された場合、または条件がfalseからtrueに変わった場合のみ次に進む。
- 条件駆動のハットブロック以外の場合は、ハットブロック内部の返り値が真の場合のみ次に進む。
- ハットブロック以外は:
- スタック内の最後のブロックの場合は:
- クリックによって実行された場合は、返り値を表示する。
- ステージモニターの更新用スレッドによって実行された場合は、更新を要求する。
- スレッドをSTATUS_RUNNINGにする。
- スタック内の最後のブロックの場合は: