マルチタスク関連講座

(1996/8/16 更新)
 ここではマルチタスクに関する話を取り上げます。とはいっても私自身専門家じゃないので いろいろおかしいところがあるとは思いますので、その点ご容赦願いますね。

・マルチタスクって? マルチタスクについての基本的な説明
・マルチタスクの方式 時間管理の考え方についての説明
・処理を管理する   処理を管理する事について

・マルチタスクって?

 よくマルチタスクといわれますが、ぶっちゃけた話「複数の処理が同時に動いているように みせる事」といっていいと思います。特にゲーム関連の分野で特に要求される技術です。
 みなさんは、プログラムを始めたばかりの初心者であった頃にわくわくしながらBASIC なんかでゲームを作った事はありませんか?仮にインベーダーみたいなものを作るとしましょう か(歳がばれる(^^; )。すると、自機、敵、弾などが必要ですね。最初はただ、これらを素直に メインループ内で順番に呼び出していくようなプログラムになっていたと思います。

    自機の処理 > 敵の処理 > 弾の処理 > 自機の処理 > 敵の処理 ・・・
   [−−−−−− これで1ループ −−−−−]

 ここで補足しておきますと、上記の仕組みは厳密には「擬似マルチ タスク」と呼ばれます。 あくまで見かけ上のマルチタスクで、処理は一度に1つずつしか行われないためです。 このページでは便宜上「マルチタスク」と短くしている事をご容赦下さいね。

 これを「超高速」で実行すると、あたかも「同時に」動いているようになります。これが マルチタスクの原理です(別に難しくはないでしょ)。

 ところで、ループさせるのはいいんですが「連続」させて実行する事はあまりありません。 理由は個々の処理の時間管理が複雑になるためです。よって「一定時間で規則正しくループを実行」 させる事が非常に重要となります。・・・では、一定時間はどうやって決定するのでしょうか? 例えば一般のビデオゲームでは、画面表示に使われる「垂直同期信号」によってタイミングを とっている場合がほとんどです。普通に使われているテレビ(NTSC)の信号では、画像の 更新周期を1/60秒としています。つまり1秒間に60枚の画像を送っているわけです (正確には多少違いますが)。という事は、垂直同期信号は1/60秒に1回発生します。 これを利用するのです。
 垂直同期信号を利用する事により、1/60秒で規則正しくループを実行させる事が可能 となります。プレイステーションの場合、VSync 関数を使う事で垂直同期を監視する事が可能 です。下記のような感じでプログラムを組めばとりあえず形にはなります。

   +> 処理1を実行
   |    |
   |  処理2を実行
   |    |
   |  処理3を実行
   |    |
   :    :
   :    :
   |    |
   |  処理nを実行
   |    |
   |  VSync(0) を実行(垂直同期を検出するまでここでストップ)
   |    |
   +−−−−+

・マルチタスクの方式

 つまり「一つの処理をある時間毎に区切り、それらのパーツを複数集めて高速に連続実行 させる事」ができればいいわけです。ここで「時間」の区切りかたによって2つの方法が あります。「コオペラティブ方式」と「プリエンプティブ方式」です。

 ・コオペラティブ方式 ・・・・・・ 時間の区切りを各処理おのおのにまかせる方式。
                   構造が簡単であるが、各処理がきちんと自分で
                   時間を管理するように組まれていなければなら
                   ない。
 ・プリエンプティブ方式 ・・・・・ 時間の区切りをシステムが強制的に行う方式。
                   各処理内で時間管理を行う必要はないが、シス
                   テムが非常に複雑になる。

 今回、私が自作したシステムは「コオペラティブ方式」を採用しています。理由は 「簡単に作れる」「ゲームでは1回の呼び出しで必要な処理を全て完了しないと動作に 支障が出るため、強制的に時間を管理されるプリエンプティブ方式では都合が悪い」 ためです。

・処理を管理する

 一般的には一つ一つの処理を大きくすると見通しが悪くなり、特にゲームのように煩雑に 変更が入るソフトでは開発が非常に困難になります。よって、処理を複数の単機能モジュールに 分解する事により、プログラムが単純になり、バグの発生を抑え、デバッグをやりやすくする 事が可能となります。

 ゲームの場合だと、先ほどの例ですと「自機の処理」「敵の処理」「弾の処理」のように 「実際に扱う物体ごと」に分けてます(まあ、分かりやすければどういう分けかたでもいいん ですが)。さて、これらを先ほどの「ループ」に組み込むのですが、普通に考えると
   +> 「自機の処理」
   |    |
   |  「敵の処理」
   |    |
   |  「弾の処理」
   |    |
   |  VSync(0) を実行(垂直同期を検出するまでここでストップ)
   |    |
   +−−−−+
 ・・・と、こうなります。敵が10匹、弾が10発ならば、
   +> 「自機の処理」
   |    |
   |  「敵1の処理」
   |    |
   |  「敵2の処理」
   |    |
   :    :
   |  「敵10の処理」
   |    |
   |  「弾1の処理」
   |    |
   |  「弾2の処理」
   |    |
   :    :
   |  「弾10の処理」
   |    |
   |  VSync(0) を実行(垂直同期を検出するまでここでストップ)
   |    |
   +−−−−+
 ・・・こうなります。けど「何かやだ」と思いませんか?このやり方だと「必要な 処理全てをループに組み込まないといけない」ですね。非常に面倒です。

 そこで「処理の実行を管理する」必要が出てきます。その働きをする処理を、 仮にタスクマネージャと呼ぶことにします。タスクマネージャは、その中でいろんな 処理の実行を行います。つまり、「自機の処理」「敵の処理」「弾の処理」などは 全てタスクマネージャから呼び出されるようにするのです。そして、ループでタスクマネージャ だけを呼び出すようにすれば、ループは非常に単純になります。
   +> タスクマネージャ
   |    |
   |  VSync(0) を実行(垂直同期を検出するまでここでストップ)
   |    |
   +−−−−+



 また続きを書きますので、今しばらくお待ち下さいませ。m(__)m


ホームに戻る