(57)【要約】【課題】スレッドの切り替え回数を抑制する。【解決手段】第１のキュー２１には、新たに発生したタスクが登録される。第２のキュー２２には、タスクに割り当てられているスレッドのうち、実行可能状態のスレッドが登録される。処理部１２は、スレッドＢ１によるタスクＡ１の実行が終了したとき、第１のキュー２１の先頭に登録されたタスクＡ１１と、第２のキュー２２の先頭に登録されたスレッドＢ２との間の実行優先度を判定し、スレッドＢ２を先に実行すべきと判定された場合、スレッドＢ２を第２のキュー２２から取り出し、スレッドＢ２によってスレッドＢ２が割り当てられたタスクＡ２を実行し、タスクＡ１１を先に実行すべきと判定された場合、タスクＡ１１を第１のキュー２１から取り出し、スレッドＢ１によってタスクＡ１１を実行する。【選択図】図１
2020161014.tif 000002
【特許請求の範囲】
【請求項１】
新たに発生したタスクが登録される第１のキューと、タスクに割り当てられているスレッドのうち、実行可能状態のスレッドが登録される第２のキューとを記憶する記憶部と、
第１のスレッドによる第１のタスクの実行が終了したとき、前記第１のキューの先頭に登録された第２のタスクと、前記第２のキューの先頭に登録された第２のスレッドとの間の実行優先度を判定し、
前記第２のスレッドを先に実行すべきと判定された場合、前記第２のスレッドを前記第２のキューから取り出し、前記第２のスレッドによって前記第２のスレッドが割り当てられたタスクを実行し、
前記第２のタスクを先に実行すべきと判定された場合、前記第２のタスクを前記第１のキューから取り出し、前記第１のスレッドによって前記第２のタスクを実行する、処理部と、
を有する情報処理装置。
【請求項２】
前記処理部は、さらに、
新規タスクが発生すると、前記新規タスクを前記第１のキューの末尾に登録するとともに、カウント値を取得するたびにカウント値が更新されるカウンタから、カウント値を取得して前記新規タスクに付加し、
前記実行可能状態のスレッドを前記第２のキューの末尾に登録する際に、前記カウンタからカウント値を取得して前記実行可能状態のスレッドに付加し、
前記実行優先度の判定では、前記第２のタスクに付加されたカウント値と前記第２のスレッドに付加されたカウント値との比較結果に基づいて前記実行優先度を判定する、
請求項１記載の情報処理装置。
【請求項３】
前記処理部は、イールドによって前記第１のスレッドによる前記第１のタスクの実行が途中で休止したとき、前記第１のスレッドを前記第２のキューの末尾に登録するとともに、前記カウンタからカウント値を取得して前記第１のスレッドに付加する、
請求項２記載の情報処理装置。
【請求項４】
前記処理部は、
待ち合わせの発生によって前記第１のスレッドによる前記第１のタスクの実行が途中で休止したとき、前記第１のスレッドをサスペンドさせて待ち合わせ状態に遷移させ、
前記第１のスレッドが待ち合わせ状態から復帰したとき、前記第１のスレッドを前記第２のキューの末尾に登録するとともに、前記カウンタからカウント値を取得して前記第１のスレッドに付加する、
請求項２記載の情報処理装置。
【請求項５】
前記処理部は、
前記第１のスレッドによる前記第１のタスクの実行が途中で休止したとき、前記実行優先度を判定し、
前記第２のスレッドを先に実行すべきと判定された場合、前記第２のスレッドを前記第２のキューから取り出し、前記第２のスレッドによって前記第２のスレッドが割り当てられたタスクを実行し、
前記第２のタスクを先に実行すべきと判定された場合、タスクに割り当てられていない第３のスレッドを前記第２のタスクに割り当て、前記第３のスレッドによって前記第２のタスクを実行する、
請求項１乃至４のいずれか１項に記載の情報処理装置。
【請求項６】
前記記憶部は、タスクに割り当てられていない未割り当てスレッドが登録される第３のキューをさらに記憶し、
前記処理部は、前記実行優先度の判定によって前記第２のスレッドを先に実行すべきと判定された場合、前記第１のスレッドを前記未割り当てスレッドとして前記第３のキューに登録する、
請求項１乃至４のいずれか１項に記載の情報処理装置。
【請求項７】
コンピュータに、
第１のスレッドによる第１のタスクの実行が終了したとき、新たに発生したタスクが登録される第１のキューの先頭に登録された第２のタスクと、タスクに割り当てられているスレッドのうち実行可能状態のスレッドが登録される第２のキューの先頭に登録された第２のスレッドとの間の実行優先度を判定し、
前記第２のスレッドを先に実行すべきと判定された場合、前記第２のスレッドを前記第２のキューから取り出し、前記第２のスレッドによって前記第２のスレッドが割り当てられたタスクを実行し、
前記第２のタスクを先に実行すべきと判定された場合、前記第２のタスクを前記第１のキューから取り出し、前記第１のスレッドによって前記第２のタスクを実行する、
処理を実行させる実行制御プログラム。
【発明の詳細な説明】
【技術分野】
【０００１】
本発明は、情報処理装置および実行制御プログラムに関する。
【背景技術】
【０００２】
コンピュータにおいて並列処理を実現するための仕組みとして、マルチスレッド方式がある。マルチスレッド方式では、複数のスレッドを用いて複数のタスクが実行される。スレッドは、プロセッサの使用単位であり、通常はスレッドごとにメモリ領域などのハードウェアリソースが割り当てられる。タスクは、処理の単位であり、タスクにスレッドが割り当てられることにより、スレッドによってタスクが実行される。
【０００３】
スレッドやタスクの実行制御に関しては、次のような提案がある。例えば、１つのスレッドによって複数のタスクを実行するようにしたデータベース管理システムが提案されている。このシステムでは、あるスレッドがタスクを実行し、その結果として、スレッド間非共有の新たなコンテキストを作成し、そのスレッドが新たなタスクを作成し、生成したコンテキストを用いて新たなタスクを生成する。
【０００４】
また、次のような情報処理装置も提案されている。この情報処理装置は、タスクを分割して得られたサブタスクを、それらの優先度に応じて複数のサブタスクキューに登録する。そして、情報処理装置は、同時実行されるサブタスク数が所定の閾値を超える場合は、優先度の高いサブタスクキューからサブタスクを取得してスレッドを作成し、サブタスクを実行させる。
【先行技術文献】
【特許文献】
【０００５】
【特許文献１】特開２０１６−４８５７７号公報
【特許文献２】特開２０１７−９０９６１号公報
【発明の概要】
【発明が解決しようとする課題】
【０００６】
ところで、マルチスレッド方式では、適正な順序でタスクが実行されることが望まれる。そのための方法として、例えば、タスクキューや、スレッド実行のための実行キューが用いられる。一例として、新規のタスクが発生すると、そのタスクがタスクキューの末尾に追加される。また、タスクキューの先頭タスクが取り出され、そのタスクに対してスレッドが割り当てられ、そのスレッドが実行キューの末尾に追加される。そして、実行キューの先頭スレッドが取り出され、そのスレッドによって対応するタスクが実行される。
【０００７】
単純な方法として、１つのタスクに１つのスレッドを割り当てる方法が考えられる。しかし、この方法では、１つのタスクの実行が終了するたびにスレッドの切り替えが発生するので、スレッドの切り替え回数が多くなるという問題がある。スレッドの切り替えの際にはコンテキストスイッチの発生によって大きなオーバヘッドが発生するので、切り替え回数が多くなるとタスクの処理性能が低下してしまう。
【０００８】
１つの側面では、スレッドの切り替え回数を抑制可能な情報処理装置および実行制御プログラムを提供することを目的とする。
【課題を解決するための手段】
【０００９】
１つの案では、記憶部と処理部とを有する情報処理装置が提供される。この情報処理装置において、記憶部は、新たに発生したタスクが登録される第１のキューと、タスクに割り当てられているスレッドのうち、実行可能状態のスレッドが登録される第２のキューとを記憶する。処理部は、第１のスレッドによる第１のタスクの実行が終了したとき、第１のキューの先頭に登録された第２のタスクと、第２のキューの先頭に登録された第２のスレッドとの間の実行優先度を判定し、第２のスレッドを先に実行すべきと判定された場合、第２のスレッドを第２のキューから取り出し、第２のスレッドによって第２のスレッドが割り当てられたタスクを実行し、第２のタスクを先に実行すべきと判定された場合、第２のタスクを第１のキューから取り出し、第１のスレッドによって第２のタスクを実行する。
【００１０】
また、１つの案では、上記の情報処理装置と同様の処理をコンピュータに実行させる実行制御プログラムが提供される。
【発明の効果】
【００１１】
１つの側面では、スレッドの切り替え回数を抑制できる。
【図面の簡単な説明】
【００１２】
【図１】第１の実施の形態に係る情報処理装置の構成例および処理例を示す図である。
【図２】第２の実施の形態に係るストレージシステムの構成例を示す図である。
【図３】ストレージ制御装置のハードウェア構成例を示す図である。
【図４】ストレージ制御装置が備える処理機能の構成例を示すブロック図である。
【図５】タスクおよびスレッドの管理について説明するための図である。
【図６】タスク実行制御の比較例を説明するための図である。
【図７】チケット番号の付加について説明するための図である。
【図８】スレッドの実行制御を示す第１の図である。
【図９】スレッドの実行制御を示す第２の図である。
【図１０】スレッドの実行制御を示す第３の図である。
【図１１】タスクの発生順の例を示す図である。
【図１２】比較例によるタスクの実行制御例を示す図である。
【図１３】第２の実施の形態によるタスクの実行制御例を示す図（その１）である。
【図１４】第２の実施の形態によるタスクの実行制御例を示す図（その２）である。
【図１５】タスク投入処理の手順を示すフローチャートの例である。
【図１６】スレッドのスケジューリング処理の手順を示すフローチャートの例（その１）である。
【図１７】スレッドのスケジューリング処理の手順を示すフローチャートの例（その２）である。
【図１８】スレッドのスケジューリング処理の手順を示すフローチャートの例（その３）である。
【図１９】スレッドによるタスク実行処理の手順を示すフローチャートの例である。
【図２０】関数実行処理の手順を示すフローチャートの例である。
【図２１】スレッドスケジューラによるスレッドの復帰判定処理の手順を示すフローチャートの例である。
【発明を実施するための形態】
【００１３】
以下、本発明の実施の形態について図面を参照して説明する。
〔第１の実施の形態〕
図１は、第１の実施の形態に係る情報処理装置の構成例および処理例を示す図である。図１に示す情報処理装置１０は、記憶部１１と処理部１２を有する。記憶部１１は、例えば、ＲＡＭ（Random Access Memory）などの記憶装置によって実現される。処理部１２は、例えばプロセッサであり、その場合、処理部１２の処理は、プロセッサがプログラムを実行することで実現される。
【００１４】
記憶部１１は、第１のキュー２１と第２のキュー２２を記憶する。第１のキュー２１には、新たに発生したタスクが登録される。図１の例では、第１のキュー２１にはタスクＡ１１，Ａ１２が登録されている。第２のキュー２２には、タスクに割り当てられているスレッドのうち、実行可能状態のスレッドが登録される。例えば、待ち合わせ状態から復帰したスレッドや、イールド（yield）によって実行が中断されて後回しになったスレッドが、第２のキュー２２に登録される。図１の例では、第２のキュー２２には、タスクＡ２に割り当てられているスレッドＢ２と、タスクＡ３に割り当てられているスレッドＢ３が登録されている。
【００１５】
処理部１２は、スレッドによるタスクの実行を制御する。例えば、図１に示すように、タスクＡ１にスレッドＢ１が割り当てられ、スレッドＢ１によってタスクＡ１が実行されているとする。この状態から、スレッドＢ１によるタスクＡ１の実行が終了すると（ステップＳ１）、処理部１２は次のような手順で、次に実行するスレッドやタスクを決定する。
【００１６】
処理部１２は、第１のキュー２１の先頭に登録されたタスクＡ１１と、第２のキュー２２の先頭に登録されたスレッドＢ２との間の実行優先度を判定する（ステップＳ２）。例えば、第１のキュー２１内の各タスク、および第２のキュー２２内の各スレッドに、実行順を示す実行順情報が付加される。この場合、処理部１２は、タスクＡ１１に付加された実行順情報とスレッドＢ２に付加された実行順情報とを比較することで、実行優先度を判定できる。
【００１７】
処理部１２は、実行優先度の判定により、スレッドＢ２を先に実行すべきと判定した場合、スレッドＢ２を第２のキュー２２から取り出し、スレッドＢ２によって、スレッドＢ２が割り当てられたタスクＡ２を実行する（ステップＳ３ａ）。この場合、実行するスレッドがスレッドＢ１からスレッドＢ２に切り替えられるので、コンテキストスイッチが発生する。なお、切り替え前のスレッドＢ１は、例えば、タスクに割り当てられていない未割り当てスレッドに遷移させて、再利用可能にしておくことができる。
【００１８】
一方、処理部１２は、実行優先度の判定により、タスクＡ１１を先に実行すべきと判定した場合、タスクＡ１１を第１のキュー２１から取り出し、タスクＡ１の実行を終了したスレッドＢ１によって、タスクＡ１１を実行する（ステップＳ３ｂ）。この場合、同じスレッドＢ１によってタスクＡ１，Ａ１１が連続的に実行されるので、実行するスレッドは切り替えられず、コンテキストスイッチも発生しない。
【００１９】
以上説明した情報処理装置１０によれば、ステップＳ３ｂのように１つのスレッドによって複数のタスクを連続的に実行できるようになる。これにより、スレッドの切り替え回数を抑制できる。
【００２０】
例えば、情報処理装置１０は、新たに発生して第１のキュー２１に登録されるタスクについては、その実行段階でスレッドを割り当てる。これにより、実行待ち状態のスレッドの発生数を抑制でき、その結果として、実行するスレッドの切り替えが発生する確率を低減できる。ただし、情報処理装置１０は、待ち合わせ状態からの復帰やイールドなどにより、スレッドが割り当て済みのタスク（すなわち、第２のキュー２２に登録されるスレッドに割り当てられたタスク）を再実行しなければならない場合がある。このため、１つのスレッドですべてのタスクを実行することはできない。すなわち、実行するスレッドの切り替えを完全に発生させないようにすることはできない。
【００２１】
そこで、情報処理装置１０は、実行優先度を判定基準として用いて、スレッドが未割り当てのタスクを既存のスレッドで実行するか、または、スレッドを切り替えてスレッドが割り当て済みのタスクを実行するかを判定する。これにより、タスクの実行順を適正化するというポリシーの下で、実行するスレッドの切り替え回数を抑制できるようになる。
【００２２】
スレッドの切り替え回数が抑制されることで、その切り替えに伴うコンテキストスイッチの発生回数も抑制され、コンテキストスイッチの発生によるオーバヘッドが小さくなる。その結果、タスクの処理性能を向上させることができる。
【００２３】
〔第２の実施の形態〕
次に、図１に示した情報処理装置１０の例としてストレージ制御装置が適用されたストレージシステムについて説明する。
【００２４】
図２は、第２の実施の形態に係るストレージシステムの構成例を示す図である。図２に示すように、第２の実施の形態に係るストレージシステムは、ホストサーバ５０と、ストレージ制御装置１００，２００と、ストレージ３００とを有する。なお、ストレージ制御装置１００，２００は、図１に示した情報処理装置１０の一例である。
【００２５】
ホストサーバ５０は、例えば、業務処理などの各種の処理を実行するサーバコンピュータである。
ストレージ制御装置１００，２００は、ホストサーバ５０から受け付けたＩ／Ｏ（Input／Output）要求を処理する。例えば、ホストサーバ５０からのアクセス対象となる１以上の論理ボリュームが、ストレージ３００の記憶領域を用いて作成される。ストレージ制御装置１００，２００は、ホストサーバ５０から論理ボリュームに対するＩ／Ｏ要求を受け付け、論理ボリュームに対するＩ／Ｏ処理を制御する。このようなストレージ制御装置１００，２００は、例えば、汎用のサーバコンピュータとして実現される。この場合、ストレージ制御装置１００，２００は、ストレージ制御用のアプリケーションプログラムを実行することで、ストレージ制御を実行する。
【００２６】
ストレージ３００には、１台以上の不揮発性記憶装置が搭載されている。例えば、ストレージ３００には、不揮発性記憶装置としてＳＳＤ（Solid State Drive）が搭載されている。
【００２７】
なお、ホストサーバ５０とストレージ制御装置１００，２００とは、例えば、ＦＣ（Fibre Channel）やｉＳＣＳＩ（Internet Small Computer System Interface）などを利用して接続される。ストレージ制御装置１００，２００は、例えば、ＦＣ、ｉＳＣＳＩ、ＬＡＮ（Local Area Network）などを利用して接続される。ストレージ制御装置１００，２００が互いに接続されていることで、例えば、データの分散配置や、データの二重化（一方から他方へのデータコピー）などが実現可能になる。ストレージ制御装置１００，２００とストレージ３００とは、例えば、ＦＣ、ｉＳＣＳＩ、ＳＡＴＡ（Serial Advanced Technology Attachment）などを利用してそれぞれ接続される。
【００２８】
図３は、ストレージ制御装置のハードウェア構成例を示す図である。なお、図３ではストレージ制御装置１００のハードウェア構成について例示するが、ストレージ制御装置２００についてもストレージ制御装置１００と同様のハードウェア構成によって実現される。
【００２９】
ストレージ制御装置１００は、ＣＰＵ（Central Processing Unit）１０１、ＲＡＭ１０２、ＳＳＤ１０３、読み取り装置１０４、ホストインタフェース（Ｉ／Ｆ）１０５、ドライブインタフェース（Ｉ／Ｆ）１０６および通信インタフェース（Ｉ／Ｆ）１０７を備える。
【００３０】
ＣＰＵ１０１は、ＲＡＭ１０２からプログラムを読み出して処理する処理装置である。ＣＰＵ１０１は、複数のコア（プロセッサコア）を備えるマルチコアＣＰＵである。
ＲＡＭ１０２は、ストレージ制御装置１００の主記憶装置として使用される。ＲＡＭ１０２には、ＣＰＵ１０１に実行させるＯＳ（Operating System）プログラムやアプリケーションプログラムの少なくとも一部が一時的に格納される。また、ＲＡＭ１０２には、ＣＰＵ１０１による処理に必要な各種データが格納される。
【００３１】
ＳＳＤ１０３は、ストレージ制御装置１００の補助記憶装置として使用される。ＳＳＤ１０３には、ＯＳプログラム、アプリケーションプログラムおよび各種データが格納される。なお、補助記憶装置としては、ＨＤＤ（Hard Disk Drive）などの他の種類の不揮発性記憶装置を使用することもできる。
【００３２】
読み取り装置１０４には、可搬型記録媒体１０４ａが脱着される。読み取り装置１０４は、可搬型記録媒体１０４ａに記録されたデータを読み取ってＣＰＵ１０１に送信する。可搬型記録媒体１０４ａとしては、光ディスク、光磁気ディスク、半導体メモリなどがある。
【００３３】
ホストインタフェース１０５は、ホストサーバ５０と通信するためのインタフェース装置である。ドライブインタフェース１０６は、ストレージ３００に含まれる不揮発性記憶装置と通信するためのインタフェース装置である。通信インタフェース１０７は、他方のストレージ制御装置２００と通信するためのインタフェース装置である。
【００３４】
図４は、ストレージ制御装置が備える処理機能の構成例を示すブロック図である。なお、図４ではストレージ制御装置１００の構成について例示するが、ストレージ制御装置２００もストレージ制御装置１００と同様の処理機能を備えている。
【００３５】
ストレージ制御装置１００は、Ｉ／Ｏ制御部１１０、スレッドプール１２１、スレッドスケジューラ１２２、チケットカウンタ１２３および記憶部１３０を備える。記憶部１３０には、タスクキュー１３１、アイドルスレッドキュー１３２、カレントスレッドポインタ１３３、実行キュー（Run Queue）１３４および待ち合わせ管理データ１３５が記憶される。
【００３６】
なお、Ｉ／Ｏ制御部１１０、スレッドプール１２１、スレッドスケジューラ１２２、チケットカウンタ１２３の処理は、例えば、ＣＰＵ１０１が所定のプログラムを実行することで実現される。記憶部１３０は、例えば、ＲＡＭ１０２の記憶領域によって実現される。
【００３７】
Ｉ／Ｏ制御部１１０は、ホストサーバ５０からのＩ／Ｏ要求に応じた論理ボリュームに対するＩ／Ｏ処理を制御する。Ｉ／Ｏ制御部１１０は、例えば、上位接続部１１１、キャッシュ管理部１１２、重複排除部１１３およびＩ／Ｏ処理部１１４を備える。
【００３８】
上位接続部１１１は、ホストサーバ５０からＩ／Ｏ要求（書き込み要求または読み出し要求）を受け付ける。キャッシュ管理部１１２は、上位接続部１１１が受け付けたＩ／Ｏ要求に応じたＩ／Ｏ処理を、ＲＡＭ１０２に確保されたキャッシュ領域を用いて制御する。重複排除部１１３は、Ｉ／Ｏ要求に応じてストレージ３００に格納されるデータの重複を排除するための制御を行う。Ｉ／Ｏ処理部１１４は、重複が排除されたデータをストレージ３００に書き込む。このとき、例えば、ＲＡＩＤ（Redundant Arrays of Inexpensive Disks）によって書き込みが制御される。また、Ｉ／Ｏ処理部１１４は、ストレージ３００からデータを読み出す。
【００３９】
スレッドプール１２１、スレッドスケジューラ１２２およびチケットカウンタ１２３は、スレッドを用いたタスクの実行を制御するための機能である。スレッドは、マルチタスクを実現するためのＣＰＵ１０１の使用単位である。各スレッドには、ＲＡＭ１０２上のメモリ領域などの個別のリソースが割り当てられる。タスクは、処理の単位であり、例えば関数や引数によって定義される。本実施の形態において、タスクは主として、Ｉ／Ｏ制御部１１０の各部で発生する単位処理である。タスクにスレッドが割り当てられることで、タスクの処理内容が実行される。スレッドは、タスクを実行する論理的な処理主体（論理プロセッサ）ということもできる。
【００４０】
スレッドプール１２１は、スレッドのリソースを管理する。スレッドプール１２１は少なくとも、アイドルスレッドキュー１３２を用いて、タスクに割り当てられていない未使用のスレッドを管理する。また、スレッドプール１２１は、タスクキュー１３１を用いて、発生したタスクを管理する。スレッドによるタスクの実行により新たなタスクが発生すると、そのタスクがスレッドプール１２１に投入される。スレッドプール１２１は、投入されたタスクをタスクキュー１３１の末尾に追加する。
【００４１】
スレッドスケジューラ１２２は、スレッドの実行を制御する。スレッドスケジューラ１２２は、実行キュー１３４を用いて、タスクに割り当て済みのスレッドの実行順を制御する。実行キュー１３４には、タスクに割り当て済みのスレッドのうち、実行可能な（実行準備ができた）スレッドが登録される。また、スレッドスケジューラ１２２は、実行キュー１３４に登録されたスレッドに対応するタスクより先に実行すべきタスクがタスクキュー１３１に登録されている場合、このタスクを先に実行するように制御する。
【００４２】
なお、スレッドスケジューラ１２２は、カレントスレッドポインタ１３３を用いて、現在実行中のスレッドを管理する。また、スレッドスケジューラ１２２は、待ち合わせ管理データ１３５を用いて、待ち合わせ状態のスレッドを管理する。
【００４３】
チケットカウンタ１２３は、チケット番号をカウントして、スレッドプール１２１およびスレッドスケジューラ１２２に発行する。チケット番号としては、順序を示すようにユニークな値が発行される。本実施の形態ではチケット番号として、カウントアップ動作により昇順の値が発行される。チケット番号は、タスクが適正な順で実行されるように、タスクキュー１３１に追加されるタスクと、実行キュー１３４に追加されるスレッドとに付加される。
【００４４】
なお、ＣＰＵ１０１がマルチプロセッサである場合、スレッドプール１２１、スレッドスケジューラ１２２およびチケットカウンタ１２３はプロセッサごとに個別に存在する。また、ＣＰＵ１０１がマルチコアＣＰＵである場合、スレッドプール１２１、スレッドスケジューラ１２２およびチケットカウンタ１２３はプロセッサコアごとに個別に存在する。
【００４５】
図５は、タスクおよびスレッドの管理について説明するための図である。
まず、タスクキュー１３１は、スレッドプール１２１に投入されたタスクを、その投入順に管理するためのキューである。図５の例では、タスクキュー１３１には先頭から順に、タスクＴＳＫ１，ＴＳＫ２，ＴＳＫ３が登録されている。これは、スレッドプール１２１に対してタスクＴＳＫ１，ＴＳＫ２，ＴＳＫ３が順番に投入されたことを示す。
【００４６】
一方、スレッドは、アイドルスレッドキュー１３２、カレントスレッドポインタ１３３および実行キュー１３４によって管理される。また、スレッドは、アイドルスレッドとワーカスレッドの２種類に大別される。アイドルスレッドは、タスクに割り当てられていない未使用のスレッドである。ワーカスレッドは、タスクに割り当てられている使用中のスレッドである。これらのうちアイドルスレッドは、アイドルスレッドキュー１３２を用いて管理される。
【００４７】
前述のように、各スレッドには個別のリソースが割り当てられる。スレッドは、メモリ領域などのリソースの獲得や初期化といった生成のためのコストが大きい。このため、スレッドプール１２１によってあらかじめ有限個のスレッドが生成されて、それらの各スレッドに対応するリソースが確保される。
【００４８】
アイドルスレッドキュー１３２は、アイドルキューを管理するためのキューである。タスクが投入される前の初期状態では、上記のように生成されたすべてのスレッドはアイドルスレッドであり、それらのアイドルスレッドがアイドルスレッドキュー１３２に登録される。そして、タスクへの割り当てが要求されると、スレッドプール１２１は、アイドルスレッドキュー１３２の先頭からアイドルスレッドを取り出し、このアイドルスレッドをタスクに割り当てる。これにより、アイドルスレッドはワーカスレッドに遷移する。また、ワーカスレッドが不要になると、スレッドプール１２１はそのワーカスレッドをアイドルスレッドキュー１３２の末尾に追加する。これにより、ワーカスレッドはアイドルスレッドに遷移する。
【００４９】
なお、図５の例では、アイドルスレッドキュー１３２には、アイドルスレッドとしてスレッドＴＨＲ１，ＴＨＲ２，ＴＨＲ３が登録されている。
カレントスレッドポインタ１３３は、ワーカスレッドのうち、現在実行中である「カレントスレッド」を指し示す。図５の例では、スレッドＴＨＲ４がカレントスレッドであり、スレッドＴＨＲ４によってタスクが実行されている。
【００５０】
実行キュー１３４は、実行待ちのワーカスレッドを、実行待ちになった順に管理するためのキューである。実行待ちのワーカスレッドとは、実行が可能な状態のタスクに割り当てられているスレッドであり、例えば、イールドが発生したスレッドや、待ち合わせ状態から復帰したスレッドがある。図５の例では、実行キュー１３４には、先頭から順にスレッドＴＨＲ５，ＴＨＲ６，ＴＨＲ７，ＴＨＲ８が登録されている。これは、実行キュー１３４に対してスレッドＴＨＲ５，ＴＨＲ６，ＴＨＲ７，ＴＨＲ８が順番に追加されたことを示す。
【００５１】
スレッドスケジューラ１２２は、実行キュー１３４の先頭から取り出したスレッド、または、タスクキュー１３１の先頭から取り出したタスクに割り当てたスレッドを、カレントスレッドポインタ１３３に接続させてカレントスレッドにし、このスレッドを実行する。また、スレッドスケジューラ１２２は、タスクの終了によってカレントスレッドが不要になった場合、カレントスレッドをスレッドプール１２１に返却する。
【００５２】
なお、マルチスレッド制御の方法には、例えば、プリエンプティブ型とノンプリエンプティブ型（協調型）とがある。プリエンプティブ型では、スレッドの実行開始後、例えば一定時間内に割り込みによって制御がスレッドからスレッドスケジューラ１２２に移る。これにより、割り込みによって実行スレッドが切り替えられる。これに対して、ノンプリエンプティブ型では、実行中のスレッド自身が制御をスレッドスケジューラ１２２に渡す。
【００５３】
本実施の形態では、スレッドスケジューラ１２２は、ノンプリエンプティブ型のマルチスレッド制御を行う。ストレージ制御装置１００では、Ｉ／Ｏ制御部１１０から実行時間の短い（粒度の小さい）タスクが大量に発生する。このため、ノンプリエンプティブ型を採用して、スレッドの切り替え制御の一部をスレッド自身が担うようにすることで、切り替え制御を効率化できる。
【００５４】
ところで、スレッドを用いたタスクの実行制御では、タスク同士や、タスクとスレッドとの間の実行順序が定まっていない場合がある。例えば、図５のようなタスクキュー１３１を用いたとしても、タスクキュー１３１の中のどの位置にタスクを挿入できるかによって、タスクの実行順が変化してしまう。また、図５のような実行キュー１３４を用いたとしても、実行キュー１３４の中のどの位置にスレッドを挿入できるかによって、スレッドやタスクの実行順が変化してしまう。このため、このように実行順序が定まっていない場合、時間的に後から投入されたタスクが先に実行される、すなわちタスクの追い越しが発生する場合がある。
【００５５】
タスクの追い越しが連続して発生して、同じタスクが何度も追い越されてしまうと、そのタスクは長時間実行待ちのままになってしまう。このように、特定のタスクが長時間実行待ちになることは、タスクの沈み込みと呼ばれる。ストレージ制御装置１００では、リードやライトなどのＩ／Ｏ処理は複数のタスクを含むが、その中の１つのタスクに沈み込みが発生すると、Ｉ／Ｏ要求に対する応答性能が悪化してしまう。これは、特定のＩ／Ｏ処理の応答時間が延びる事象を発生させるだけでなく、応答時間の異なるＩ／Ｏ処理が混在することで応答性能が不安定に見えるという事象も発生させる。このため、タスクの沈み込みをできるだけ発生させないようにすることが望まれる。
【００５６】
タスクを投入順に実行するための方法として、タスクキュー１３１および実行キュー１３４に対しては新たなエントリを常に末尾に登録するとともに、１タスクに１アイドルスレッドを割り当てるようにする方法が考えられる。ここで、図６を用いて、このような方法を用いた場合のタスク実行制御の比較例について説明する。
【００５７】
図６は、タスク実行制御の比較例を説明するための図である。なお、図６では、図５に示した構成を用いてタスク実行制御を行うものとして説明する。
図６の例では、スレッドプール１２１に対してタスクＴＳＫ１，ＴＳＫ２が順に登録されたとする。その結果、状態ＳＴ１に示すように、タスクキュー１３１には先頭からタスクＴＳＫ１，ＴＳＫ２が登録される。また、状態ＳＴ１では、アイドルスレッドキュー１３２にスレッドＴＨＲ５〜ＴＨＲ７が登録されているとする。
【００５８】
この状態から、スレッドプール１２１に対してタスクＴＳＫ３が投入されたとする。この場合、状態ＳＴ２に示すように、タスクキュー１３１の末尾にタスクＴＳＫ３が追加される。
【００５９】
また、タスクキュー１３１に登録された各スレッドにはスレッドプール１２１からスレッドが割り当てられ、そのスレッドが実行キュー１３４の末尾に追加される。状態ＳＴ２からは、状態ＳＴ３に示すように、タスクキュー１３１の先頭からタスクＴＳＫ１が取り出され、このタスクＴＳＫ１に対して、アイドルスレッドキュー１３２から取り出されたスレッドＴＨＲ５が割り当てられる。そして、状態ＳＴ４に示すように、タスクＴＳＫ１に割り当て済みのスレッドＴＨＲ５が、実行キュー１３４の末尾に追加される。
【００６０】
また、図示しないが、この後、タスクＴＳＫ２にスレッドＴＨＲ６が割り当てられ、そのスレッドＴＨＲ６が実行キュー１３４の末尾に追加される。さらに、タスクＴＳＫ３にスレッドＴＨＲ７が割り当てられ、そのスレッドＴＨＲ７が実行キュー１３４の末尾に追加される。図６の比較例では基本的に、タスクキュー１３１に大量のタスクが登録された場合、残っているアイドルスレッドのすべてがタスクキュー１３１のタスクに割り当てられ、それらのスレッドが実行キュー１３４に登録される。
【００６１】
スレッドスケジューラ１２２は、実行キュー１３４の先頭からスレッドを１つずつ取り出して実行する。状態ＳＴ４では、スレッドＴＨＲ１が実行中であり、実行キュー１３４には先頭から順にスレッドＴＨＲ２，ＴＨＲ３，ＴＨＲ４，ＴＨＲ５が登録されている。この状態からスレッドＴＨＲ１によるタスクの実行が終了したとすると、スレッドＴＨＲ１はアイドルスレッドキュー１３２の末尾に追加されて、アイドルスレッドに戻される。そして、実行キュー１３４の先頭からスレッドＴＨＲ２が取り出されてカレントスレッドポインタ１３３に接続され、スレッドＴＨＲ２の実行が開始される。さらにその後、実行キュー１３４から同様の手順でスレッドＴＨＲ３，ＴＨＲ４，ＴＨＲ５が順に取り出され、実行される。また、タスクの実行が終了したスレッドは、アイドルスレッドに戻される。
【００６２】
このように、タスクが投入された順にタスクにスレッドが割り当てられ、そのスレッドが実行キュー１３４の末尾に追加されることで、タスクの投入順にタスクを実行することができる。これにより、タスクの沈み込みが発生する可能性を低減できる。
【００６３】
しかしながら、図６の方法では、スレッドに割り当てられたタスクが終了するたびに、スレッドが切り替えられ、コンテキストスイッチが発生する。コンテキストスイッチでは、レジスタの書き替えなどが行われるため、処理負荷が大きい。また、多くのタスクを並列処理しようとするほどスレッドの数が多くなり、その分だけコンテキストスイッチの発生回数も多くなる。例えば、前述のようにストレージ制御では各タスクの粒度が小さく、しかも多くのＩ／Ｏ処理が短時間に発生することから、数千個から数万個のスレッドが生成され得る。このため、コンテキストスイッチの発生回数も増大し、その分の処理のオーバヘッドが大きくなって、Ｉ／Ｏ処理性能が低下する。さらに、スレッドに割り当てられたタスクが終了するたびに、アイドルスレッドキュー１３２へのスレッドの追加が行われるため、オーバヘッドはさらに大きくなってしまう。
【００６４】
タスクの粒度が小さいことから、タスクの実行時間に対してオーバヘッドは相対的に大きく、Ｉ／Ｏ処理性能への影響が大きい。そのため、性能改善のためにスレッドの実行数（ワーカスレッドの数）を低減して、スレッドの切り替えやアイドルスレッドへの遷移の回数を少なくすることが望まれる。さらに、スレッドの数が多いほど必要なメモリ領域が大きくなる。スレッドによってメモリ領域が圧迫されると、それ以外の処理のためのメモリ領域のローカリティが低下し、キャッシュミスやページフォールトが頻出する原因となる。このような観点からも、スレッドの数を低減することが望まれる。
【００６５】
また、図６の方法を用いた場合でも、タスクの実行順が適正でなくなる場合がある。例えば、スレッドは、タスクの実行中に待ち合わせが発生して、サスペンドする場合がある。サスペンドしたスレッドが待ち合わせ状態から復帰すると、そのスレッドは実行キュー１３４の末尾に追加される。また、スレッドのイールドが発生するとスレッドの処理は後回しにされ、そのスレッドが実行キュー１３４の末尾に追加される。このように、タスクキュー１３１内のタスクに新たに割り当てられたスレッドだけでなく、タスクに割り当て済みのスレッドも実行キュー１３４に登録されることが原因となって、本来実行すべき順でタスクが実行されないケースが起こり得る。
【００６６】
例えば、アイドルスレッドが枯渇して新規のタスクにスレッドを割り当てられない状態が発生すると、タスクがスレッドプール１２１に投入された後に、待ち合わせから復帰したスレッドまたはイールドが発生したスレッドが、実行キュー１３４に追加される場合がある。この場合、待ち合わせ状態から復帰したスレッドまたはイールドが発生したスレッドに割り当てられたタスクは、新規に投入されたタスクより先に実行されてしまい、タスクの実行順は本来実行すべき順序とは違ってしまう。また、タスクキュー１３１からタスクを取り出してスレッドを割り当てる、という処理に時間がかかることによって、そのスレッドを実行キュー１３４に登録するまでに遅延が発生することもあり得る。この場合にも、待ち合わせ状態から復帰したスレッドまたはイールドが発生したスレッドに割り当てられたタスクが先に実行キュー１３４に登録されて実行されてしまい、タスクの実行順が適正でなくなることがあり得る。
【００６７】
すなわち、ここでいう「タスクの実行順が適正」とは、スレッドプール１２１に対する新規タスクの投入時刻と、スレッドが割り当て済みのタスクが実行キュー１３４に追加される時刻との間での前後関係が守られるように、タスクが実行されることを示す。図６の方法を用いた場合でも、このような時間的な前後関係が変化した状態でタスクが実行されてしまう可能性がある。
【００６８】
そこで、本実施の形態のストレージ制御装置１００は、以下の図７〜図１０に示す処理により、タスクの実行順を適正化しつつ、スレッドの実行数を低減する。
図７は、チケット番号の付加について説明するための図である。ストレージ制御装置１００では、タスクの実行順を適正化するために、チケットカウンタ１２３が用いられる。チケットカウンタ１２３は、タスクやスレッドの実行順（実行優先度）を示すチケット番号を発行するカウンタである。本実施の形態において、チケットカウンタ１２３は、昇順のチケット番号を発行する。この場合、チケット番号が小さいほど実行優先度が高い。チケット番号は、タスクキュー１３１に登録されるタスク、および実行キュー１３４に登録されるスレッドに付加される。
【００６９】
例えば、図７に示すように、スレッドプール１２１に対して新規のタスクが投入され、そのタスクがタスクキュー１３１の末尾に登録されたとき、そのタスクに対して、チケットカウンタ１２３から発行されたチケット番号が付加される。図７の例では、新規のタスクＴＳＫ７がタスクキュー１３１に追加されたとき、タスクＴＳＫ７に対してチケット番号「５」が付加されている。
【００７０】
また、図７に示すように、イールドの発生や待ち合わせ状態からの復帰によってスレッドが実行キュー１３４の末尾に登録されたとき、そのスレッドに対して、チケットカウンタ１２３から発行されたチケット番号が付加される。図７の例では、タスクＴＳＫ７の投入直後のタイミングで、タスクＴＳＫ４に割り当てられたスレッドＴＨＲ４が実行キュー１３４の末尾に追加されたとする。この場合、スレッドＴＨＲ４に対してチケット番号「６」が付加される。
【００７１】
このような処理により、タスクキュー１３１のタスク、およびタスクに割り当てられた実行キュー１３４のスレッドのそれぞれに対して、正しい実行順を示すチケット番号が付加されるようになる。ここでいう「正しい実行順」とは、スレッドプール１２１に対するタスクの投入タイミングや、イールドの発生または待ち合わせ状態からの復帰のタイミングについて、時系列的な順序が一致していることを示す。
【００７２】
図８は、スレッドの実行制御を示す第１の図である。
図８では、スレッドＴＨＲ１によってタスクＴＳＫ１が実行されているとする。そして、イールドや待ち合わせが発生せず、タスクＴＳＫ１の実行が終了したとする。このとき、タスクキュー１３１の先頭のタスクＴＳＫ７に付加されたチケット番号「２」と、実行キュー１３４の先頭のスレッドＴＨＲ２に付加されたチケット番号「３」とが比較される。この比較により、タスクＴＳＫ７と、スレッドＴＨＲ２が割り当てられたタスクＴＳＫ２のどちらを先に実行すべきかが判定される。
【００７３】
図８の例では、タスクＴＳＫ７に付加されたチケット番号「２」の方が小さいので、タスクＴＳＫ７を先に実行すべきと判定される。この場合、タスクキュー１３１からタスクＴＳＫ７が取り出され、そのタスクＴＳＫ７に対して、タスクＴＳＫ１の実行を終了したスレッドＴＨＲ１が割り当てられる。そして、スレッドＴＨＲ１をそのまま用いてタスクＴＳＫ７が実行される。このケースでは、同一のカレントスレッドによって異なるタスクが連続して実行されるので、スレッドの切り替えが発生せず、その切り替えに伴うコンテキストスイッチも発生しない。
【００７４】
図９は、スレッドの実行制御を示す第２の図である。
図９では、図８の手順でスレッドＴＨＲ１によってタスクＴＳＫ７が実行されているとする。そして、イールドや待ち合わせが発生せず、タスクＴＳＫ７の実行が終了したとする。このとき、タスクキュー１３１の先頭のタスクＴＳＫ８に付加されたチケット番号「４」と、実行キュー１３４の先頭のスレッドＴＨＲ２に付加されたチケット番号「３」とが比較される。この比較により、タスクＴＳＫ８と、スレッドＴＨＲ２が割り当てられたタスクＴＳＫ２のどちらを先に実行すべきかが判定される。
【００７５】
図９の例では、スレッドＴＨＲ２に付加されたチケット番号「３」の方が小さいので、スレッドＴＨＲ２を先に実行すべきと判定される。この場合、カレントスレッドであるスレッドＴＨＲ１はアイドルスレッドキュー１３２に追加されて、アイドルキューに戻される。そして、実行キュー１３４からスレッドＴＨＲ２が取り出され、このスレッドＴＨＲ２がカレントスレッドとなって、タスクＴＳＫ２が実行される。
【００７６】
図１０は、スレッドの実行制御を示す第３の図である。
図１０では、図９の手順でスレッドＴＨＲ２によってタスクＴＳＫ２が実行されているとする。そして、スレッドＴＨＲ２のイールドまたは待ち合わせが発生したとする。このとき、タスクキュー１３１の先頭のタスクＴＳＫ８に付加されたチケット番号「４」と、実行キュー１３４の先頭のスレッドＴＨＲ３に付加されたチケット番号「５」とが比較される。この比較により、タスクＴＳＫ８と、スレッドＴＨＲ３が割り当てられたタスクＴＳＫ３のどちらを先に実行すべきかが判定される。
【００７７】
図１０の例では、タスクＴＳＫ８に付加されたチケット番号「４」の方が小さいので、タスクＴＳＫ８を先に実行すべきと判定される。この場合、カレントスレッドであるスレッドＴＨＲ２はサスペンド状態となる。イールド発生の場合、スレッドＴＨＲ２は実行キュー１３４の末尾に追加される。待ち合わせ発生の場合、スレッドＴＨＲ２は待ち合わせ管理データ１３５の管理下に入る。また、タスクキュー１３１からタスクＴＳＫ８が取り出されるとともに、アイドルスレッドキュー１３２からアイドルスレッド（ここではスレッドＴＨＲ５）が取り出されて、タスクＴＳＫ８に対してスレッドＴＨＲ５が割り当てられる。そして、スレッドＴＨＲ５がカレントスレッドとなって、タスクＴＳＫ８が実行される。
【００７８】
以上の図７〜図１０に示した処理によれば、実行キュー１３４にはすでにタスクに割り当て済みのスレッドしか登録されず、タスクキュー１３１に登録された新規のタスクに対しては、そのタスクを実行する段階でスレッドが割り当てられる。タスクに対するスレッドの割り当てにかかる時間は、タスクが投入されてからタスクの実行が開始されるまでのどの段階でスレッド割り当てが行われたとしても、変わらない。そのため、タスクの実行段階でスレッドを割り当てることで、スレッド割り当ての処理負荷を増やすことなく、新規のワーカスレッドの発生数を可能な限り抑制できる。その結果、ワーカスレッドの同時発生数を低減できる。
【００７９】
また、図８のケースのように、カレントスレッドから実行すべきタスクが解放されたとき、タスクキュー１３１のタスクは同じカレントスレッドを用いて実行される。このように１つのスレッドで複数のタスクを連続して実行できる仕組みを設けたことにより、ワーカスレッドの同時発生数をさらに低減できる。
【００８０】
ワーカスレッドの同時発生数の低減は、ワーカスレッドが多い分だけ実行スレッドの切り替え回数が多くなるという意味で、間接的にコンテキストスイッチの発生回数の低減に寄与する。また、図８のケースでは、スレッドを切り替えずにタスクを連続実行できるので、図８の処理は直接的にコンテキストスイッチの発生回数の低減に寄与する。いずれにしても、コンテキストスイッチの発生回数が低減されることで、その発生によるオーバヘッドを小さくすることができ、その結果としてストレージ制御におけるＩ／Ｏ処理性能を向上させることができる。
【００８１】
また、図７〜図１０に示した処理によれば、タスクキュー１３１に追加されるタスクと、実行キュー１３４に追加されるスレッドに対して、実行優先度を示すチケット番号が付加される。そして、タスクキュー１３１の先頭タスクと実行キュー１３４の先頭スレッドとの間でチケット番号が比較され、その比較結果によって、先頭タスクと、先頭スレッドが割り当てられているタスクのどちらを先に実行するかが判定される。このような仕組みにより、タスクの実行順を適正化できる。すなわち、スレッドプール１２１に対する新規タスクの投入時刻と、スレッドが割り当て済みのタスクが実行キュー１３４に追加される時刻との間での前後関係が守られるように、タスクの実行順を制御できる。
【００８２】
特に、図８のケースでは、実行キュー１３４内のスレッドが割り当てられたタスクより実行優先度の高いタスクキュー１３１内のタスクを先に実行でき、なおかつ、そのタスクを現在のカレントスレッドによって連続的に実行できる。したがって、タスクやスレッドへのチケット番号の付加と、タスクキュー１３１の先頭タスクと実行キュー１３４の先頭スレッドとの間のチケット番号の比較は、タスク実行順の適正化とコンテキストスイッチの発生回数低減の両方に寄与する。
【００８３】
ここで、タスク実行順の適正化についての具体例を示す。
図１１は、タスクの発生順の例を示す図である。
図１１の例では、スレッドＴＨＲ１１によってタスクＴＳＫ１１が実行されている状態から、スレッドプール１２１に対して新規のタスクＴＳＫ１２，ＴＳＫ１３が順に投入される。次に、タスクＴＳＫ１に割り当てられたスレッドＴＨＲ１が待ち合わせ状態から復帰する。次に、スレッドプール１２１に対して新規のタスクＴＳＫ１４が投入される。次に、タスクＴＳＫ２に割り当てられたスレッドＴＨＲ２が待ち合わせ状態から復帰し、さらにタスクＴＳＫ３に割り当てられたスレッドＴＨＲ３が待ち合わせ状態から復帰する。次に、スレッドプール１２１に対して新規のタスクＴＳＫ１５が投入される。次に、タスクＴＳＫ４に割り当てられたスレッドＴＨＲ４が待ち合わせ状態から復帰する。次に、スレッドプール１２１に対して新規のタスクＴＳＫ１６が投入される。
【００８４】
なお、第２の実施の形態のストレージ制御装置１００では、上記のタスクの発生順にしたがってチケット番号「１」〜「９」が発行される。図１１においてタスクＴＳＫ１〜ＴＳＫ４に付加されているチケット番号「３」，「５」，「６」，「８」は、実際にはスレッドＴＨＲ１〜ＴＨＲ４に付加される。
【００８５】
図１２は、比較例によるタスクの実行制御例を示す図である。この図１２は、図６に示した比較例の処理によって図１１のタスクの実行を制御した場合を示す。なお、比較例の処理では、図１１に示されたチケット番号は付加されない。また、スレッドプール１２１にタスクが投入された場合、そのタスクが一旦タスクキュー１３１に登録された後、そのタスクにスレッドが割り当てられるが、図１２の説明ではタスクキュー１３１への登録を省略する。
【００８６】
図１２の初期状態では、スレッドＴＨＲ１１によってタスクＴＳＫ１１が実行中であり、アイドルスレッドキュー１３２に登録されているアイドルスレッドの数が「３」であるとする。この状態から、スレッドプール１２１にタスクＴＳＫ１２が投入されると、タスクＴＳＫ１２に対してアイドルスレッドキュー１３２からスレッドＴＨＲ１２が割り当てられ、スレッドＴＨＲ１２が実行キュー１３４に追加される。このとき、アイドルスレッドの数は「２」に減少する（状態ＳＴ１１）。
【００８７】
次に、スレッドプール１２１にタスクＴＳＫ１３が投入されると、タスクＴＳＫ１３に対してアイドルスレッドキュー１３２からスレッドＴＨＲ１３が割り当てられ、スレッドＴＨＲ１３が実行キュー１３４に追加される。このとき、アイドルスレッドの数は「１」に減少する（状態ＳＴ１２）。次に、タスクＴＳＫ１に割り当てられたスレッドＴＨＲ１が待ち合わせ状態から復帰すると、スレッドＴＨＲ１が実行キュー１３４に追加される（状態ＳＴ１３）。
【００８８】
次に、スレッドプール１２１にタスクＴＳＫ１４が投入されると、タスクＴＳＫ１４に対してアイドルスレッドキュー１３２からスレッドＴＨＲ１４が割り当てられ、スレッドＴＨＲ１４が実行キュー１３４に追加される。このとき、アイドルスレッドの数は「０」に減少する（状態ＳＴ１４）。次に、タスクＴＳＫ２に割り当てられたスレッドＴＨＲ２が待ち合わせ状態から復帰すると、スレッドＴＨＲ２が実行キュー１３４に追加される（状態ＳＴ１５）。次に、タスクＴＳＫ３に割り当てられたスレッドＴＨＲ３が待ち合わせ状態から復帰すると、スレッドＴＨＲ３が実行キュー１３４に追加される（状態ＳＴ１６）。
【００８９】
次に、スレッドプール１２１にタスクＴＳＫ１５が投入され、タスクＴＳＫ１５がタスクキュー１３１に登録される。しかし、このときアイドルスレッドが残っていないので、タスクＴＳＫ１５にスレッドを割り当てることができず、タスクＴＳＫ１５はタスクキュー１３１に登録されたままになる（状態ＳＴ１７）。次に、タスクＴＳＫ４に割り当てられたスレッドＴＨＲ４が待ち合わせ状態から復帰すると、スレッドＴＨＲ４が実行キュー１３４に追加される（状態ＳＴ１８）。
【００９０】
次に、スレッドプール１２１にタスクＴＳＫ１６が投入され、タスクＴＳＫ１６がタスクキュー１３１に登録される。しかし、このときアイドルスレッドが残っていないので、タスクＴＳＫ１６にスレッドを割り当てることができず、タスクＴＳＫ１６はタスクキュー１３１に登録されたままになる（状態ＳＴ１９）。
【００９１】
次に、スレッドＴＨＲ１１によるタスクＴＳＫ１１の実行が終了したとする。タスクＴＳＫ１１の終了によりスレッドＴＨＲ１１は不要になり、スレッドＴＨＲ１１はアイドルスレッドキュー１３２に登録されてアイドルスレッドになる。これにより、アイドルスレッドの数は「１」に増加し、タスクキュー１３１のタスクＴＳＫ１５にスレッドを割り当て可能になる。したがって、タスクキュー１３１からタスクＴＳＫ１５が取り出され、タスクＴＳＫ１５に対してアイドルスレッドキュー１３２からスレッドＴＨＲ１１が割り当てられ、スレッドＴＨＲ１１が実行キュー１３４に追加される。このとき、アイドルスレッドの数は再度「０」となる。また、実行キュー１３４の先頭からスレッドＴＨＲ１２が取り出され、スレッドＴＨＲ１２によってタスクＴＳＫ１２が実行される（状態ＳＴ２０）。
【００９２】
次に、タスクＴＳＫ１２を実行中のスレッドＴＨＲ１２にイールドが発生し、スレッドＴＨＲ１２が実行キュー１３４の末尾に追加されたとする。このとき、実行キュー１３４の先頭からスレッドＴＨＲ１３が取り出され、スレッドＴＨＲ１３によりタスクＴＳＫ１３が実行される（状態ＳＴ２１）。
【００９３】
これ以後、実行キュー１３４からスレッドが順次取り出されて、取り出されたスレッドによってタスクが実行される。したがって、タスクＴＳＫ１，ＴＳＫ１４，ＴＳＫ２，ＴＳＫ３，ＴＳＫ４，ＴＳＫ１５，ＴＳＫ１２の順に実行される。図１１でのタスクの順序と比較すると、タスクＴＳＫ１５とタスクＴＳＫ４との順序が入れ替わっており、タスクが正しい順序で実行されていないことがわかる。また、図１２の状態ＳＴ２１ではタスクＴＳＫ１６にはスレッドが割り当てられていないので、タスクＴＳＫ１６の投入後にイールドしたスレッドＴＨＲ１２が割り当てられたタスクＴＳＫ１２は、タスクＴＳＫ１６より先に実行されてしまう。
【００９４】
以上の図１２は、アイドルスレッドが枯渇して新規タスクに対するスレッドの割り当てが不可能になることによって、タスクの実行順が変化してしまう場合について例示した。しかし、他の例として、新規タスクに対するスレッドの割り当て処理にかかる時間によって、タスクの実行順が変化する場合もある。例えば、あるタスクが投入されてスレッドの割り当て処理が開始された後、別のスレッドが待ち合わせ状態から復帰したとする。このとき、スレッドの割り当て処理が完了する前に復帰したスレッドが実行キュー１３４に追加されてしまうと、タスクの実行順が変化してしまう。
【００９５】
図１３、図１４は、第２の実施の形態によるタスクの実行制御例を示す図である。図１３、図１４は、第２の実施の形態のストレージ制御装置１００において図１１のタスクの実行を制御した場合を示す。
【００９６】
図１３の初期状態では、図１２の初期状態と同様に、スレッドＴＨＲ１１によってタスクＴＳＫ１１が実行中であり、アイドルスレッドキュー１３２に登録されているアイドルスレッドの数が「３」であるとする。この状態から、スレッドプール１２１にタスクＴＳＫ１２が投入されると、タスクＴＳＫ１２はタスクキュー１３１に追加され、チケット番号「１」がタスクＴＳＫ１２に付加される（状態ＳＴ３１）。次に、スレッドプール１２１にタスクＴＳＫ１３が投入されると、タスクＴＳＫ１３はタスクキュー１３１に追加され、チケット番号「２」がタスクＴＳＫ１３に付加される（状態ＳＴ３２）。
【００９７】
次に、タスクＴＳＫ１に割り当てられたスレッドＴＨＲ１が待ち合わせ状態から復帰すると、スレッドＴＨＲ１が実行キュー１３４に追加され、チケット番号「３」がスレッドＴＨＲ１に付加される（状態ＳＴ３３）。次に、スレッドプール１２１にタスクＴＳＫ１４が投入されると、タスクＴＳＫ１４はタスクキュー１３１に追加され、チケット番号「４」がタスクＴＳＫ１４に付加される（状態ＳＴ３４）。
【００９８】
次に、タスクＴＳＫ２に割り当てられたスレッドＴＨＲ２が待ち合わせ状態から復帰すると、スレッドＴＨＲ２が実行キュー１３４に追加され、チケット番号「５」がスレッドＴＨＲ２に付加される（状態ＳＴ３５）。次に、タスクＴＳＫ３に割り当てられたスレッドＴＨＲ３が待ち合わせ状態から復帰すると、スレッドＴＨＲ３が実行キュー１３４に追加され、チケット番号「６」がスレッドＴＨＲ３に付加される（状態ＳＴ３６）。
【００９９】
次に、スレッドプール１２１にタスクＴＳＫ１５が投入されると、タスクＴＳＫ１５はタスクキュー１３１に追加され、チケット番号「７」がタスクＴＳＫ１５に付加される（状態ＳＴ３７）。次に、タスクＴＳＫ４に割り当てられたスレッドＴＨＲ４が待ち合わせ状態から復帰すると、スレッドＴＨＲ４が実行キュー１３４に追加され、チケット番号「８」がスレッドＴＨＲ４に付加される（状態ＳＴ３８）。次に、スレッドプール１２１にタスクＴＳＫ１６が投入されると、タスクＴＳＫ１６はタスクキュー１３１に追加され、チケット番号「９」がタスクＴＳＫ１６に付加される（状態ＳＴ３９）。
【０１００】
次に、スレッドＴＨＲ１１によるタスクＴＳＫ１１の実行が終了し、スレッドＴＨＲ１１が不要になったとする。このとき、タスクキュー１３１の先頭のタスクＴＳＫ１２に付加されたチケット番号「１」と、実行キュー１３４の先頭のスレッドＴＨＲ１に付加されたチケット番号「３」とが比較される。この例ではタスクＴＳＫ１２に付加されたチケット番号「１」の方が小さいので、タスクＴＳＫ１２を先に実行すべきと判定される。この場合、タスクキュー１３１からタスクＴＳＫ１２が取り出され、タスクＴＳＫ１２に対して、タスクＴＳＫ１１の実行を終了したスレッドＴＨＲ１１が割り当てられ、スレッドＴＨＲ１１をそのまま用いてタスクＴＳＫ１２が実行される（状態ＳＴ４０）。同一のカレントスレッドによって２つのタスクが連続して実行されるので、スレッドの切り替えが発生せず、その切り替えに伴うコンテキストスイッチも発生しない。
【０１０１】
次に、タスクＴＳＫ１２を実行中のスレッドＴＨＲ１１にイールドが発生し、スレッドＴＨＲ１１が実行キュー１３４の末尾に追加されたとする。スレッドＴＨＲ１１にはチケット番号「１０」が付加される。このとき、タスクキュー１３１の先頭のタスクＴＳＫ１３に付加されたチケット番号「２」と、実行キュー１３４の先頭のスレッドＴＨＲ１に付加されたチケット番号「３」とが比較される。この例ではタスクＴＳＫ１３に付加されたチケット番号「２」の方が小さいので、タスクＴＳＫ１３を先に実行すべきと判定される。この場合、タスクキュー１３１からタスクＴＳＫ１３が取り出されるとともに、アイドルスレッドキュー１３２からアイドルスレッド（ここではスレッドＴＨＲ１２）が取り出される。そして、タスクＴＳＫ１３に対してスレッドＴＨＲ１２が割り当てられ、スレッドＴＨＲ１２によってタスクＴＳＫ１３が実行される。このとき、アイドルスレッドの数は「２」に減少する（状態ＳＴ４１）。
【０１０２】
以下、図１４を用いて説明を続ける。
次に、スレッドＴＨＲ１２によるタスクＴＳＫ１３の実行が終了し、スレッドＴＨＲ１２が不要になったとする。このとき、タスクキュー１３１の先頭のタスクＴＳＫ１４に付加されたチケット番号「４」と、実行キュー１３４の先頭のスレッドＴＨＲ１に付加されたチケット番号「３」とが比較される。この例ではスレッドＴＨＲ１に付加されたチケット番号「３」の方が小さいので、スレッドＴＨＲ１を先に実行すべきと判定される。この場合、スレッドＴＨＲ１２はアイドルスレッドキュー１３２に追加されてアイドルキューに戻される。これにより、アイドルスレッドの数は「３」に増加する。また、実行キュー１３４からスレッドＴＨＲ１が取り出され、スレッドＴＨＲ１によってタスクＴＳＫ１が実行される（状態ＳＴ４２）。
【０１０３】
次に、タスクＴＳＫ１を実行中のスレッドＴＨＲ１にイールドが発生し、スレッドＴＨＲ１が実行キュー１３４の末尾に追加されたとする。このとき、タスクキュー１３１の先頭のタスクＴＳＫ１４に付加されたチケット番号「４」と、実行キュー１３４の先頭のスレッドＴＨＲ２に付加されたチケット番号「５」とが比較される。この例ではタスクＴＳＫ１４に付加されたチケット番号「４」の方が小さい。この場合、タスクキュー１３１からタスクＴＳＫ１４が取り出されるとともに、アイドルスレッドキュー１３２からアイドルスレッド（ここではスレッドＴＨＲ１３）が取り出され、スレッドＴＨＲ１３によってタスクＴＳＫ１４が実行される。このとき、アイドルスレッドの数は「２」に減少する（状態ＳＴ４３）。
【０１０４】
次に、タスクＴＳＫ１４を実行中のスレッドＴＨＲ１３にイールドが発生し、スレッドＴＨＲ１３が実行キュー１３４の末尾に追加されたとする。このとき、タスクキュー１３１の先頭のタスクＴＳＫ１５に付加されたチケット番号「７」と、実行キュー１３４の先頭のスレッドＴＨＲ２に付加されたチケット番号「５」とが比較される。この例ではスレッドＴＨＲ２に付加されたチケット番号「５」の方が小さい。この場合、実行キュー１３４からスレッドＴＨＲ２が取り出され、スレッドＴＨＲ２によってタスクＴＳＫ２が実行される（状態ＳＴ４４）。
【０１０５】
次に、タスクＴＳＫ２を実行中のスレッドＴＨＲ２にイールドが発生し、スレッドＴＨＲ２が実行キュー１３４の末尾に追加されたとする。このとき、タスクキュー１３１の先頭のタスクＴＳＫ１５に付加されたチケット番号「７」と、実行キュー１３４の先頭のスレッドＴＨＲ３に付加されたチケット番号「６」とが比較される。この例ではスレッドＴＨＲ３に付加されたチケット番号「６」の方が小さい。この場合、実行キュー１３４からスレッドＴＨＲ３が取り出され、スレッドＴＨＲ３によってタスクＴＳＫ３が実行される（状態ＳＴ４５）。
【０１０６】
次に、タスクＴＳＫ３を実行中のスレッドＴＨＲ３にイールドが発生し、スレッドＴＨＲ３が実行キュー１３４の末尾に追加されたとする（図示せず）。このとき、タスクキュー１３１の先頭のタスクＴＳＫ１５に付加されたチケット番号「７」と、実行キュー１３４の先頭のスレッドＴＨＲ４に付加されたチケット番号「８」とが比較される。この例ではタスクＴＳＫ１５に付加されたチケット番号「７」の方が小さい。この場合、タスクキュー１３１からタスクＴＳＫ１５が取り出されるとともに、アイドルスレッドキュー１３２からアイドルスレッド（ここではスレッドＴＨＲ１４）が取り出され、スレッドＴＨＲ１４によってタスクＴＳＫ１５が実行される。このとき、アイドルスレッドの数は「１」に減少する（状態ＳＴ４６）。
【０１０７】
タスクＴＳＫ１５を実行中のスレッドＴＨＲ１４にイールドが発生し、スレッドＴＨＲ１４が実行キュー１３４の末尾に追加されたとする（図示せず）。このとき、タスクキュー１３１の先頭のタスクＴＳＫ１６に付加されたチケット番号「９」と、実行キュー１３４の先頭のスレッドＴＨＲ４に付加されたチケット番号「８」とが比較される。この例ではスレッドＴＨＲ４に付加されたチケット番号「８」の方が小さい。この場合、実行キュー１３４からスレッドＴＨＲ４が取り出され、スレッドＴＨＲ４によってタスクＴＳＫ４が実行される（状態ＳＴ４７）。
【０１０８】
以上の図１３、図１４の処理によれば、タスクが図１１に示した順序と同じ順序で実行される。特に、図１２の処理ではタスクＴＳＫ１５，ＴＳＫ４の実行順が入れ替わっていたが、図１４ではこれらの実行順が入れ替わらない。また、図１４の状態ＳＴ４７の後では、タスクＴＳＫ１６のチケット番号「９」とスレッドＴＨＲ１１のチケット番号「１０」との比較に応じてタスクＴＳＫ１６が先に実行されるので、この点でも図１２の処理からタスク実行順が改善される。このように、本実施の形態のストレージ制御装置１００によれば、タスクの実行順を適正化できる。
【０１０９】
さらに、図１２の処理と比較して、図１３、図１４の処理によればアイドルスレッドがタスクに割り当てられる数が少なくなるので、スレッドの同時使用数（ワーカスレッドの同時発生数）を低減できる。これは、新規に投入されたタスクに対しては実行段階でスレッドが割り当てられ、なおかつその際に、既存のカレントスレッドを割り当てて、そのカレントスレッドによってタスクを実行可能な場合があるからである。例えば、図１３の状態ＳＴ４０では、同じスレッドＴＨＲ１１によってタスクＴＳＫ１１，ＴＳＫ１２が連続して実行されている。これにより、スレッドの切り替え回数を低減でき、その結果、コンテキストスイッチの発生回数が低減されて、その発生によるオーバヘッドを抑制できる。したがって、ストレージ制御装置１００のＩ／Ｏ処理性能を向上させることができる。
【０１１０】
次に、ストレージ制御装置１００の処理についてフローチャートを用いて説明する。
まず、図１５は、タスク投入処理の手順を示すフローチャートの例である。図１５の処理は、スレッドプール１２１に新規のタスクが投入されると開始される。
【０１１１】
［ステップＳ１１］スレッドプール１２１は、チケットカウンタ１２３からチケット番号を取得する。
［ステップＳ１２］スレッドプール１２１は、チケットカウンタ１２３をカウントアップする。
【０１１２】
［ステップＳ１３］スレッドプール１２１は、取得したチケット番号を、投入されたタスクに付加する。
［ステップＳ１４］スレッドプール１２１は、チケット番号が付加されたタスクをタスクキュー１３１の末尾に追加する。
【０１１３】
図１６〜図１８は、スレッドのスケジューリング処理の手順を示すフローチャートの例である。
［ステップＳ２１］スレッドスケジューラ１２２は、実行キュー１３４が空かを判定する。スレッドスケジューラ１２２は、実行キュー１３４が空の場合、ステップＳ２２の処理を実行し、実行キュー１３４にスレッドが登録されている場合、図１７のステップＳ３１の処理を実行する。
【０１１４】
［ステップＳ２２］スレッドスケジューラ１２２は、タスクキュー１３１が空かをスレッドプール１２１に問い合わせる。スレッドスケジューラ１２２は、スレッドプール１２１からの返答に基づき、タスクキュー１３１が空の場合、ステップＳ２１の処理を実行し、タスクキュー１３１にタスクが登録されている場合、ステップＳ２３の処理を実行する。
【０１１５】
［ステップＳ２３］スレッドスケジューラ１２２は、スレッドプール１２１を通じて、タスクキュー１３１の先頭タスクを読み出す。具体的には、関数を示すポインタや関数の引数など、タスクに関する情報が読み出される。
【０１１６】
［ステップＳ２４］スレッドスケジューラ１２２は、アイドルスレッドキュー１３２が空かをスレッドプール１２１に問い合わせる。スレッドスケジューラ１２２は、スレッドプール１２１からの返答に基づき、アイドルスレッドキュー１３２が空の場合、ステップＳ２１の処理を実行し、アイドルスレッドキュー１３２にアイドルスレッドが登録されている場合、ステップＳ２５の処理を実行する。
【０１１７】
［ステップＳ２５］スレッドスケジューラ１２２は、スレッドプール１２１を通じて、アイドルスレッドキュー１３２から先頭のアイドルスレッドを取り出す。
［ステップＳ２６］スレッドスケジューラ１２２は、ステップＳ２３で読み出したタスクをタスクキュー１３１から除去するようにスレッドプール１２１に依頼する。これにより、該当タスクがタスクキュー１３１から取り出される（除去される）。
【０１１８】
［ステップＳ２７］スレッドスケジューラ１２２は、ステップＳ２３で読み出したタスクに対して、ステップＳ２５で取り出したスレッドを割り当てる。具体的には、スレッドに対し、そのスレッドの引数として、タスクが示す関数ポインタや関数の引数が引き渡される。
【０１１９】
［ステップＳ２８］スレッドに制御が移され（ＣＰＵリソースが明け渡され）、スレッドによってタスクが実行される。その後、制御がスレッドスケジューラ１２２に戻ると、スレッドスケジューラ１２２はステップＳ２１の処理を実行する。
【０１２０】
以上の図１６の処理では、実行キュー１３４が空であり、タスクキュー１３１にタスクが登録されている場合、タスクキュー１３１から取り出されたタスクにアイドルスレッドが割り当てられ、このスレッドによってタスクが実行される。
【０１２１】
以下、図１７を用いて説明を続ける。
［ステップＳ３１］スレッドスケジューラ１２２は、実行キュー１３４の先頭スレッドを読み出す。具体的には、スレッドの引数（タスクが示す関数ポインタ、関数の引数を含む）やスレッドに付加されたチケット番号が読み出される。
【０１２２】
［ステップＳ３２］スレッドスケジューラ１２２は、タスクキュー１３１が空かをスレッドプール１２１に問い合わせる。スレッドスケジューラ１２２は、スレッドプール１２１からの返答に基づき、タスクキュー１３１が空の場合、図１８のステップＳ４１の処理を実行し、タスクキュー１３１にタスクが登録されている場合、ステップＳ３３の処理を実行する。
【０１２３】
［ステップＳ３３］スレッドスケジューラ１２２は、スレッドプール１２１を通じて、タスクキュー１３１の先頭タスクを読み出す。具体的には、関数を示すポインタや関数の引数、付加されたチケット番号など、タスクに関する情報が読み出される。
【０１２４】
［ステップＳ３４］スレッドスケジューラ１２２は、ステップＳ３１で読み出したスレッドのチケット番号と、ステップＳ３３で読み出したタスクのチケット番号とを比較する。スレッドスケジューラ１２２は、タスクのチケット番号の方が小さい場合、ステップＳ３５の処理を実行し、スレッドのチケット番号の方が小さい場合、図１８のステップＳ４１の処理を実行する。
【０１２５】
［ステップＳ３５］スレッドスケジューラ１２２は、アイドルスレッドキュー１３２が空かをスレッドプール１２１に問い合わせる。スレッドスケジューラ１２２は、スレッドプール１２１からの返答に基づき、アイドルスレッドキュー１３２が空の場合、図１８のステップＳ４１の処理を実行し、アイドルスレッドキュー１３２にアイドルスレッドが登録されている場合、ステップＳ３６の処理を実行する。
【０１２６】
［ステップＳ３６］スレッドスケジューラ１２２は、スレッドプール１２１を通じて、アイドルスレッドキュー１３２から先頭のアイドルスレッドを取り出す。
［ステップＳ３７］スレッドスケジューラ１２２は、ステップＳ３３で読み出したタスクをタスクキュー１３１から除去するようにスレッドプール１２１に依頼する。これにより、該当タスクがタスクキュー１３１から取り出される（除去される）。
【０１２７】
［ステップＳ３８］スレッドスケジューラ１２２は、ステップＳ３３で読み出したタスクに対して、ステップＳ３６で取り出したスレッドを割り当てる。具体的には、スレッドに対し、そのスレッドの引数として、タスクが示す関数ポインタや関数の引数が引き渡される。
【０１２８】
［ステップＳ３９］スレッドに制御が移され、スレッドによってタスクが実行される。その後、制御がスレッドスケジューラ１２２に戻ると、スレッドスケジューラ１２２は図１６のステップＳ２１の処理を実行する。
【０１２９】
以下、図１８を用いて説明を続ける。
［ステップＳ４１］スレッドスケジューラ１２２は、ステップＳ３１で読み出したスレッドを実行キュー１３４から除去する。
【０１３０】
［ステップＳ４２］ステップＳ３１で読み出されたスレッドに制御が移され、このスレッドによってタスクが実行される。その後、制御がスレッドスケジューラ１２２に戻ると、スレッドスケジューラ１２２は図１６のステップＳ２１の処理を実行する。
【０１３１】
以上の図１７、図１８の処理では、タスクキュー１３１および実行キュー１３４のいずれも空でない場合には、タスクキュー１３１の先頭タスクのチケット番号と実行キュー１３４の先頭スレッドのチケット番号とが比較される。先頭タスクのチケット番号の方が小さく、アイドルスレッドが残っている場合には、アイドルスレッドが取り出され、そのスレッドによって先頭タスクが実行される（ステップＳ３９）。先頭スレッドのチケット番号の方が小さい場合、および、先頭タスクのチケット番号の方が小さいがアイドルスレッドが残っていない場合には、先頭スレッドが実行される（ステップＳ４２）。
【０１３２】
図１９は、スレッドによるタスク実行処理の手順を示すフローチャートの例である。図１９の処理は、図１６のステップＳ２８、図１７のステップＳ３９、図１８のステップＳ４２の処理に対応する。
【０１３３】
［ステップＳ５１］スレッドによる関数実行処理が行われる。
ここで、ステップＳ５１の処理が終了した状態とは、スレッドが割り当てられていたタスクに含まれる処理が終了し、スレッドが解放された状態である。ステップＳ５１の処理が終了すると、解放されたスレッドによりステップＳ５２〜Ｓ５９の処理が実行される。なお、ステップＳ５１の終了時点で制御がスレッドからスレッドスケジューラ１２２に一時的に戻され、ステップＳ５２〜Ｓ５９の処理がスレッドスケジューラ１２２によって実行されてもよい。
【０１３４】
［ステップＳ５２］スレッドは、タスクキュー１３１が空かをスレッドプール１２１に問い合わせる。スレッドは、スレッドプール１２１からの返答に基づき、タスクキュー１３１が空の場合、ステップＳ５９の処理を実行し、タスクキュー１３１にタスクが登録されている場合、ステップＳ５３の処理を実行する。
【０１３５】
［ステップＳ５３］スレッドは、スレッドプール１２１を通じて、タスクキュー１３１の先頭タスクを読み出す。具体的には、関数を示すポインタや関数の引数、付加されたチケット番号など、タスクに関する情報が読み出される。
【０１３６】
［ステップＳ５４］スレッドは、実行キュー１３４が空かを判定する。スレッドは、実行キュー１３４が空の場合、ステップＳ５７の処理を実行し、実行キュー１３４にスレッドが登録されている場合、ステップＳ５５の処理を実行する。
【０１３７】
［ステップＳ５５］スレッドは、実行キュー１３４の先頭スレッドを読み出す。具体的には、スレッドの引数やスレッドに付加されたチケット番号が読み出される。
［ステップＳ５６］スレッドは、ステップＳ５３で読み出したタスクのチケット番号と、ステップＳ５５で読み出したスレッドのチケット番号とを比較する。スレッドは、タスクのチケット番号の方が小さい場合、ステップＳ５７の処理を実行し、スレッドのチケット番号の方が小さい場合、ステップＳ５９の処理を実行する。前者の場合、タスクキュー１３１の先頭タスクの実行優先度が高いと判定され、後者の場合、実行キュー１３４の先頭スレッドが割り当てられたタスクの実行優先度が高いと判定される。
【０１３８】
［ステップＳ５７］スレッドは、ステップＳ５３で読み出したタスクをタスクキュー１３１から除去するようにスレッドプール１２１に依頼する。これにより、該当タスクがタスクキュー１３１から取り出される（除去される）。
【０１３９】
［ステップＳ５８］スレッドは、ステップＳ５３で読み出したタスクに対して、自分自身（カレントスレッド）を割り当てる。具体的には、スレッドに対し、そのスレッドの引数として、タスクが示す関数ポインタや関数の引数が引き渡される。
【０１４０】
この後、処理がステップＳ５１に進められ、ステップＳ５３で読み出したタスクに対応する関数が、同じスレッドによって実行される。すなわち、同じスレッドによって複数のタスクが連続的に実行される。この場合、ステップＳ５３で読み出したタスクの実行時にコンテキストスイッチが発生しない。
【０１４１】
［ステップＳ５９］スレッドはサスペンドし、自分自身をアイドルスレッドキュー１３２に登録するようにスレッドプール１２１に依頼する。これにより、スレッドはアイドルスレッドキュー１３２の末尾に追加されて、アイドルスレッドに遷移する。この後、制御がスレッドスケジューラ１２２に戻され、処理が図１６のステップＳ２１に進められる。
【０１４２】
ここで、ステップＳ５６，Ｓ５９の順に処理が行われた場合、その後に図１６のステップＳ２１で実行キュー１３４が空でないと判定され、さらに図１７のステップＳ３１〜Ｓ３９が実行されることで、実行キュー１３４の先頭スレッドが実行される。一方、ステップＳ５２，Ｓ５９の順に処理が行われた場合には、図１６のステップＳ２１での判定結果は確定されない。そして、ステップＳ２１で実行キュー１３４が空でないと判定された場合には、図１７のステップＳ３１〜Ｓ３９が実行されることで、同様に実行キュー１３４の先頭スレッドが実行される。いずれのケースでも、ステップＳ５９でスレッドがサスペンドし、ステップＳ３９で別のスレッドが実行されることで、コンテキストスイッチが発生する。
【０１４３】
一方、ステップＳ５８で現状のカレントスレッドがタスクキュー１３１の先頭タスクに割り当てられ、ステップＳ５１でカレントスレッドにより先頭タスクが実行されるケースでは、同一のスレッドによって複数のタスクが連続的に実行される。この場合、スレッドの切り替えが発生しないので、スレッド切り替えに伴うコンテキストスイッチを発生させずに複数のタスクを連続的に実行できる。
【０１４４】
図２０は、関数実行処理の手順を示すフローチャートの例である。図２０の処理は、図１９のステップＳ５１の処理に対応する。
［ステップＳ６１］スレッドは、自分自身に対応付けられた関数ポインタおよび関数の引数に基づいて、関数を実行する。
【０１４５】
［ステップＳ６２］待ち合わせが発生した場合、処理がステップＳ６３に進められる。待ち合わせが発生しなかった場合、処理がステップＳ６４に進められる。
［ステップＳ６３］スレッドはサスペンドし、スレッド自身の情報を待ち合わせ管理データ１３５に登録することで、待ち合わせ状態に遷移する。この後、制御がスレッドスケジューラ１２２に戻され、処理が図１６のステップＳ２１に進められる。
【０１４６】
［ステップＳ６４］イールドが発生した場合、スレッドによるタスクの処理が途中で休止され、処理がステップＳ６５に進められる。イールドが発生しなかった場合、すなわち、ステップＳ６１での関数の処理が終了した場合には、関数実行処理が終了し、処理が図１９のステップＳ５２に進められる。
【０１４７】
［ステップＳ６５］スレッドは、チケットカウンタ１２３からチケット番号を取得する。
［ステップＳ６６］スレッドは、チケットカウンタ１２３をカウントアップする。
【０１４８】
［ステップＳ６７］スレッドは、取得したチケット番号を自分自身に付加する。
［ステップＳ６８］スレッドはサスペンドし、チケット番号が付加された自分自身を実行キュー１３４の末尾に追加する。この後、制御がスレッドスケジューラ１２２に戻され、処理が図１６のステップＳ２１に進められる。
【０１４９】
ここで、スレッドの待ち合わせの例について補足説明する。
ここでは例として、特定のハードウェアとの間で通信を行うタスクに割り当てられたスレッドの待ち合わせについて説明する。以下の処理は、特定のハードウェアと通信するためのインタフェース回路との間で実行される。例えば、特定のハードウェアとしてホストサーバ５０と通信する場合、ホストサーバ５０と通信するためのホストインタフェース１０５との間で以下の処理が実行される。
【０１５０】
ＲＡＭ１０２には、上記のインタフェース回路に対応する完了キューが用意される。完了キューは、インタフェース回路に対してタスクが依頼した処理が完了した場合に、その完了を示すエントリが登録されるキューである。また、待ち合わせ管理データ１３５には、インタフェース回路に対応する待ち合わせ管理キューが含まれる。待ち合わせ管理キューは、サスペンドして待ち合わせ状態になったスレッドに対応するエントリが登録されるキューである。なお、通信先の特定のハードウェアが複数存在する場合、完了キューおよび待ち合わせ管理キューは、ハードウェアのそれぞれに対応するインタフェース回路ごとに用意される。
【０１５１】
スレッドは、インタフェース回路に対して処理を依頼するタスクを実行すると、依頼した処理が完了したことを示すエントリが完了キューにあるかを確認する。インタフェース回路は、スレッドから処理が依頼されると、その処理を実行し、実行が完了すると、完了メッセージをスレッドから指定された受信バッファ上の領域に格納するとともに、処理が完了したことを示すエントリを完了キューに登録する。このエントリには、処理の依頼元のスレッドの識別情報が含まれる。
【０１５２】
例えば、インタフェース回路は、スレッドから上記のハードウェアからのデータ受信が依頼されると、依頼されたデータをハードウェアから受信する。インタフェース回路は、データ受信が完了すると、完了メッセージと受信したデータとを受信バッファに格納するとともに、依頼元のスレッドの識別情報とを含むエントリを完了キューに登録する。スレッドは、スレッド自身の識別情報を含むエントリが完了キューにない場合、サスペンドし、スレッド自身を示すエントリを待ち合わせ管理キューに登録することで待ち合わせ状態になる。待ち合わせ管理キューのエントリには、スレッドの識別情報と、受信バッファにおける、完了メッセージや受信データの格納先アドレスが含まれる。
【０１５３】
図２０の処理では、ステップＳ６１において、インタフェース回路に処理を依頼するための関数が実行される。そして、この関数の実行が完了したことを示すエントリが完了キューに登録されていない場合、ステップＳ６２で「Ｙｅｓ」と判定され、ステップＳ６３でスレッドが待ち合わせ管理キューに登録される。
【０１５４】
一方、スレッドスケジューラ１２２は、間欠的なタイミングで完了キューをポーリングし、待ち合わせ管理キューに登録されたスレッドに対応するエントリが完了キューに登録されているかを確認する。該当するエントリが完了キューに登録されていた場合、スレッドスケジューラ１２２は、エントリに対応するスレッドを待ち合わせ管理キューから取り出し、そのスレッドを実行キュー１３４の末尾に登録する。これにより、スレッドは待ち合わせ状態から復帰する。スレッドは、実行キュー１３４から取り出されたときに、受信バッファ上の完了メッセージや受信データを用いて、タスクに含まれる後続の処理を実行する。
【０１５５】
図２１は、スレッドスケジューラによるスレッドの復帰判定処理の手順を示すフローチャートの例である。
［ステップＳ７１］スレッドスケジューラ１２２は、待ち合わせ状態のスレッドのうち、復帰するスレッドがあるかを判定する。上記の待ち合わせの例では、スレッドスケジューラ１２２が完了キューをポーリングし、待ち合わせ管理キューに登録されたスレッドに対応するエントリが完了キューに登録されている場合、そのスレッドを復帰するスレッドと判定する。スレッドスケジューラ１２２は、復帰するスレッドがある場合、ステップＳ７２の処理を実行し、復帰するスレッドがない場合、復帰判定処理を終了する。
【０１５６】
［ステップＳ７２］スレッドスケジューラ１２２は、チケットカウンタ１２３からチケット番号を取得する。
［ステップＳ７３］スレッドスケジューラ１２２は、チケットカウンタ１２３をカウントアップする。
【０１５７】
［ステップＳ７４］スレッドスケジューラ１２２は、復帰すると判定されたスレッドを待ち合わせ管理データ１３５から取り出し、取得したチケット番号をそのスレッドに付加する。上記の待ち合わせの例では、このとき、復帰すると判定されたスレッドが待ち合わせ管理キューから取り出される（待ち合わせ管理キューからは除去される）。
【０１５８】
［ステップＳ７５］スレッドスケジューラ１２２は、チケット番号が付加されたスレッドを実行キュー１３４の末尾に追加する。これにより、スレッドは待ち合わせ状態から復帰する。
【０１５９】
図２１の復帰判定処理は、例えば、次のようなタイミングで実行される。
ノンプリエンプティブ型（協調型）のマルチスレッド制御では、一例として、スレッドの実行が終了して制御がスレッドスケジューラ１２２に戻ったときに、復帰可能なスレッドがあるかを確認する、というルールが採用される。このルールにしたがえば、図１６のステップＳ２８、図１７のステップＳ３９、図１８のステップＳ４２でのスレッドによるタスクの実行が終了して、制御がスレッドスケジューラ１２２に戻ったときに、図２１の処理が実行されればよい。ただし、本実施の形態では、同一のスレッドが複数のタスクを連続的に実行し得る。このため、さらに、スレッドが１つのタスクの実行を終了してから、同じスレッドが次のタスクを実行するまでの期間に、図２１の処理が実行される。例えば、図１９におけるステップＳ５７の実行直前からステップＳ５８の実行直後までの期間に、図２１の処理が実行されればよい。この場合、図２１の処理は、スレッドスケジューラ１２２の代わりにスレッドが実行してもよい。
【０１６０】
また、別の方法として、タスクの関数が実行されるたびに図２１の処理が実行されてもよい。例えば、図２０のステップＳ６１における関数の実行が終了するたびに、図２１の処理が実行される。この場合にも、図２１の処理は、スレッドスケジューラ１２２の代わりにスレッドが実行してもよい。
【０１６１】
なお、上記の各実施の形態に示した装置（例えば、情報処理装置１０、ストレージ制御装置１００，２００）の処理機能は、コンピュータによって実現することができる。その場合、各装置が有すべき機能の処理内容を記述したプログラムが提供され、そのプログラムをコンピュータで実行することにより、上記処理機能がコンピュータ上で実現される。処理内容を記述したプログラムは、コンピュータで読み取り可能な記録媒体に記録しておくことができる。コンピュータで読み取り可能な記録媒体としては、磁気記憶装置、光ディスク、光磁気記録媒体、半導体メモリなどがある。磁気記憶装置には、ハードディスク装置（ＨＤＤ）、磁気テープなどがある。光ディスクには、ＣＤ（Compact Disc）、ＤＶＤ（Digital Versatile Disc）、ブルーレイディスク（Blu-ray Disc：ＢＤ、登録商標）などがある。光磁気記録媒体には、ＭＯ（Magneto-Optical disk）などがある。
【０１６２】
プログラムを流通させる場合には、例えば、そのプログラムが記録されたＤＶＤ、ＣＤなどの可搬型記録媒体が販売される。また、プログラムをサーバコンピュータの記憶装置に格納しておき、ネットワークを介して、サーバコンピュータから他のコンピュータにそのプログラムを転送することもできる。
【０１６３】
プログラムを実行するコンピュータは、例えば、可搬型記録媒体に記録されたプログラムまたはサーバコンピュータから転送されたプログラムを、自己の記憶装置に格納する。そして、コンピュータは、自己の記憶装置からプログラムを読み取り、プログラムにしたがった処理を実行する。なお、コンピュータは、可搬型記録媒体から直接プログラムを読み取り、そのプログラムにしたがった処理を実行することもできる。また、コンピュータは、ネットワークを介して接続されたサーバコンピュータからプログラムが転送されるごとに、逐次、受け取ったプログラムにしたがった処理を実行することもできる。
【０１６４】
以上の各実施の形態に関し、さらに以下の付記を開示する。
（付記１）  新たに発生したタスクが登録される第１のキューと、タスクに割り当てられているスレッドのうち、実行可能状態のスレッドが登録される第２のキューとを記憶する記憶部と、
第１のスレッドによる第１のタスクの実行が終了したとき、前記第１のキューの先頭に登録された第２のタスクと、前記第２のキューの先頭に登録された第２のスレッドとの間の実行優先度を判定し、
前記第２のスレッドを先に実行すべきと判定された場合、前記第２のスレッドを前記第２のキューから取り出し、前記第２のスレッドによって前記第２のスレッドが割り当てられたタスクを実行し、
前記第２のタスクを先に実行すべきと判定された場合、前記第２のタスクを前記第１のキューから取り出し、前記第１のスレッドによって前記第２のタスクを実行する、処理部と、
を有する情報処理装置。
【０１６５】
（付記２）  前記処理部は、さらに、
新規タスクが発生すると、前記新規タスクを前記第１のキューの末尾に登録するとともに、カウント値を取得するたびにカウント値が更新されるカウンタから、カウント値を取得して前記新規タスクに付加し、
前記実行可能状態のスレッドを前記第２のキューの末尾に登録する際に、前記カウンタからカウント値を取得して前記実行可能状態のスレッドに付加し、
前記実行優先度の判定では、前記第２のタスクに付加されたカウント値と前記第２のスレッドに付加されたカウント値との比較結果に基づいて前記実行優先度を判定する、
付記１記載の情報処理装置。
【０１６６】
（付記３）  前記処理部は、イールドによって前記第１のスレッドによる前記第１のタスクの実行が途中で休止したとき、前記第１のスレッドを前記第２のキューの末尾に登録するとともに、前記カウンタからカウント値を取得して前記第１のスレッドに付加する、
付記２記載の情報処理装置。
【０１６７】
（付記４）  前記処理部は、
待ち合わせの発生によって前記第１のスレッドによる前記第１のタスクの実行が途中で休止したとき、前記第１のスレッドをサスペンドさせて待ち合わせ状態に遷移させ、
前記第１のスレッドが待ち合わせ状態から復帰したとき、前記第１のスレッドを前記第２のキューの末尾に登録するとともに、前記カウンタからカウント値を取得して前記第１のスレッドに付加する、
付記２記載の情報処理装置。
【０１６８】
（付記５）  前記処理部は、
前記第１のスレッドによる前記第１のタスクの実行が途中で休止したとき、前記実行優先度を判定し、
前記第２のスレッドを先に実行すべきと判定された場合、前記第２のスレッドを前記第２のキューから取り出し、前記第２のスレッドによって前記第２のスレッドが割り当てられたタスクを実行し、
前記第２のタスクを先に実行すべきと判定された場合、タスクに割り当てられていない第３のスレッドを前記第２のタスクに割り当て、前記第３のスレッドによって前記第２のタスクを実行する、
付記１乃至４のいずれか１つに記載の情報処理装置。
【０１６９】
（付記６）  前記記憶部は、タスクに割り当てられていない未割り当てスレッドが登録される第３のキューをさらに記憶し、
前記処理部は、前記実行優先度の判定によって前記第２のスレッドを先に実行すべきと判定された場合、前記第１のスレッドを前記未割り当てスレッドとして前記第３のキューに登録する、
付記１乃至４のいずれか１つに記載の情報処理装置。
【０１７０】
（付記７）  コンピュータに、
第１のスレッドによる第１のタスクの実行が終了したとき、新たに発生したタスクが登録される第１のキューの先頭に登録された第２のタスクと、タスクに割り当てられているスレッドのうち実行可能状態のスレッドが登録される第２のキューの先頭に登録された第２のスレッドとの間の実行優先度を判定し、
前記第２のスレッドを先に実行すべきと判定された場合、前記第２のスレッドを前記第２のキューから取り出し、前記第２のスレッドによって前記第２のスレッドが割り当てられたタスクを実行し、
前記第２のタスクを先に実行すべきと判定された場合、前記第２のタスクを前記第１のキューから取り出し、前記第１のスレッドによって前記第２のタスクを実行する、
処理を実行させる実行制御プログラム。
【０１７１】
（付記８）  前記コンピュータに、
新規タスクが発生すると、前記新規タスクを前記第１のキューの末尾に登録するとともに、カウント値を取得するたびにカウント値が更新されるカウンタから、カウント値を取得して前記新規タスクに付加し、
前記実行可能状態のスレッドを前記第２のキューの末尾に登録する際に、前記カウンタからカウント値を取得して前記実行可能状態のスレッドに付加する、
処理をさらに実行させ、
前記実行優先度の判定では、前記第２のタスクに付加されたカウント値と前記第２のスレッドに付加されたカウント値との比較結果に基づいて前記実行優先度を判定する、
付記７記載の実行制御プログラム。
【０１７２】
（付記９）  前記コンピュータに、
イールドによって前記第１のスレッドによる前記第１のタスクの実行が途中で休止したとき、前記第１のスレッドを前記第２のキューの末尾に登録するとともに、前記カウンタからカウント値を取得して前記第１のスレッドに付加する、
処理をさらに実行させる付記８記載の実行制御プログラム。
【０１７３】
（付記１０）  前記コンピュータに、
待ち合わせの発生によって前記第１のスレッドによる前記第１のタスクの実行が途中で休止したとき、前記第１のスレッドをサスペンドさせて待ち合わせ状態に遷移させ、
前記第１のスレッドが待ち合わせ状態から復帰したとき、前記第１のスレッドを前記第２のキューの末尾に登録するとともに、前記カウンタからカウント値を取得して前記第１のスレッドに付加する、
処理をさらに実行させる付記８記載の実行制御プログラム。
【０１７４】
（付記１１）  前記コンピュータに、
前記第１のスレッドによる前記第１のタスクの実行が途中で休止したとき、前記実行優先度を判定し、
前記第２のスレッドを先に実行すべきと判定された場合、前記第２のスレッドを前記第２のキューから取り出し、前記第２のスレッドによって前記第２のスレッドが割り当てられたタスクを実行し、
前記第２のタスクを先に実行すべきと判定された場合、タスクに割り当てられていない第３のスレッドを前記第２のタスクに割り当て、前記第３のスレッドによって前記第２のタスクを実行する、
処理をさらに実行させる付記７乃至１０のいずれか１つに記載の実行制御プログラム。
【０１７５】
（付記１２）  前記コンピュータに、
前記実行優先度の判定によって前記第２のスレッドを先に実行すべきと判定された場合、タスクに割り当てられていない未割り当てスレッドが登録される第３のキューに対して、前記第１のスレッドを前記未割り当てスレッドとして登録する、
処理をさらに実行させる付記７乃至１０のいずれか１つに記載の実行制御プログラム。
【符号の説明】
【０１７６】
１０  情報処理装置
１１  記憶部
１２  処理部
２１  第１のキュー
２２  第２のキュー
Ａ１〜Ａ３，Ａ１１，Ａ１２  タスク
Ｂ１〜Ｂ３  スレッド
【図１】
2020161014.tif 000003
【図２】
2020161014.tif 000004
【図３】
2020161014.tif 000005
【図４】
2020161014.tif 000006
【図５】
2020161014.tif 000007
【図６】
2020161014.tif 000008
【図７】
2020161014.tif 000009
【図８】
2020161014.tif 000010
【図９】
2020161014.tif 000011
【図１０】
2020161014.tif 000012
【図１１】
2020161014.tif 000013
【図１２】
2020161014.tif 000014
【図１３】
2020161014.tif 000015
【図１４】
2020161014.tif 000016
【図１５】
2020161014.tif 000017
【図１６】
2020161014.tif 000018
【図１７】
2020161014.tif 000019
【図１８】
2020161014.tif 000020
【図１９】
2020161014.tif 000021
【図２０】
2020161014.tif 000022
【図２１】
2020161014.tif 000023