(57)【特許請求の範囲】
【請求項１】
個々のデータの行列からなるデータ用キューを格納するメモリと、
生成したデータを前記データ用キューに入れるデータ生成スレッドと、データを前記データ用キューから取り出すデータ消費スレッドと、の少なくともいずれかを処理する１つ以上のプロセッサと、を備え、
前記プロセッサは、
前記データ消費スレッドの処理において、前記データ用キューに取り出すべきデータが存在する場合は当該データを取り出し、前記データ用キューに取り出すべきデータが存在しない場合は当該データ用キューに前記データ消費スレッドの識別情報を入れ、
前記データ生成スレッドの処理において、生成したデータを前記データ用キューに入れる際、当該データ用キューに前記データ消費スレッドの識別情報が入っていなかったら生成したデータを当該データ用キューに入れ、当該データ用キューに前記識別情報が入っていたら、生成したデータの格納先を、当該データ消費スレッドがアクセス可能な別の記憶領域へ変更することを特徴とする情報処理装置。
【請求項２】
前記プロセッサは、前記データ消費スレッドの処理において前記データ用キューに当該データ消費スレッドの識別情報を入れた後、当該データ消費スレッドの処理を休止することを特徴とする請求項１に記載の情報処理装置。
【請求項３】
前記プロセッサは、前記データ生成スレッドの処理において、前記データ用キューに前記データ消費スレッドの識別情報が入っていたら、休止していた当該データ消費スレッドの処理を再開する状態へと移行させることを特徴とする請求項２に記載の情報処理装置。
【請求項４】
前記プロセッサは、
前記データ生成スレッドの処理における、データをデータ用キューに入れる操作および、前記データ消費スレッドの処理における、データをデータ用キューから取り出す操作を、あらかじめ定めたアトミック操作の単位で複数段階に分けて実施し、当該アトミック操作期間外では、前記データをデータ用キューに入れる操作または前記データをデータ用キューから取り出す操作の途中であっても、別のスレッド処理のためのデータ用キューに対する操作を妨げないことを特徴とする請求項１から３のいずれかに記載の情報処理装置。
【請求項５】
前記プロセッサは、前記別のスレッドの処理において、
前記アトミック操作期間外であっても当該別のスレッド処理のためのデータ用キューに対する操作を行えない場合、前記データをデータ用キューに入れる操作または前記データをデータ用キューから取り出す操作の途中の状態であると判断し、当該途中の状態に応じて定められた操作を行うことにより、前記データをデータ用キューに入れる操作または前記データをデータ用キューから取り出す操作の少なくとも一部を進捗させることを特徴とする請求項４に記載の情報処理装置。
【請求項６】
前記データ用キューは、各データを、行列における次のデータへのポインタで連結したリンクリストの構造を有し、各ポインタの更新をそれぞれアトミック操作とすることで、前記データをデータ用キューに入れる操作および前記データをデータ用キューから取り出す操作を複数段階に分けて実施することを特徴とする請求項４または５に記載の情報処理装置。
【請求項７】
前記メモリは、前記データ用キューに入れるべき所定単位のデータを格納できる、空きの記憶領域の情報を表す空きパケットの行列からなるパケット用キューをさらに格納し、
前記プロセッサは、
前記データ生成スレッドの処理において、生成した所定単位のデータを前記データ用キューに入れる前に、前記パケット用キューから空きパケットの取り出しを試み、取り出すべき空きパケットが存在する場合はそれを取り出し、取り出すべき空きパケットが存在しない場合は当該パケット用キューに前記データ生成スレッドの識別情報を入れ、
前記データ消費スレッドの処理において、所定単位のデータを前記データ用キューから取り出した後、不要になった空きパケットを前記パケット用キューに戻す際、当該パケット用キューに前記データ生成スレッドの識別情報が入っていなかったら空きパケットを当該パケット用キューに戻し、当該パケット用キューに前記識別情報が入っていたら、空きパケットの格納先を、当該データ生成スレッドがアクセス可能な別の記憶領域へ変更することを特徴とする請求項１から６のいずれかに記載の情報処理装置。
【請求項８】
前記データ用キューは、各データを、行列における次のデータへのポインタで連結したリンクリストの構造を有し、
前記データ用キューには、前記取り出すべきデータおよび前記データ消費スレッドの識別情報のいずれも入っていない状態においてダミーのデータが格納され、
前記リンクリストにおける前記ダミーのデータへのポインタには、ダミーのデータを識別する情報が付加されていることを特徴とする請求項１から５のいずれかに記載の情報処理装置。
【請求項９】
前記データ用キューは、各データを、行列における次のデータへのポインタで連結したリンクリストの構造を有し、
前記プロセッサは、
前記データ消費スレッドの処理において、前記データ用キューに前記データ消費スレッドの識別情報を入れた際、前記リンクリストにおける当該識別情報へのポインタに、識別情報が入っていることを示す情報を付加し、
前記データ生成スレッドの処理において、前記リンクリストのポインタを参照することにより、前記データ用キューに前記データ消費スレッドの識別情報が入っているか否かを判断することを特徴とする請求項１から５のいずれかに記載の情報処理装置。
【請求項１０】
プロセッサによる第１のスレッドの処理において、メモリに格納されたキューからのデータ取り出しを試みた際、当該キューに取り出すべきデータが存在する場合は当該データを取り出し、取り出すべきデータが存在しない場合は前記第１のスレッドの識別情報を当該キューに入れるステップと、
プロセッサによる第２のスレッドの処理において、前記キューへデータを入れる際、当該キューに前記第１のスレッドの識別情報が入っていなかったらデータを当該キューに入れ、当該キューに前記第１のスレッドの識別情報が入っていたら、当該第１のスレッドにデータを渡すステップと、
を含むことを特徴とする情報処理方法。
【請求項１１】
第１のスレッドの処理において、メモリに格納されたキューからのデータ取り出しを試みた際、当該キューに取り出すべきデータが存在する場合は当該データを取り出し、取り出すべきデータが存在しない場合は前記第１のスレッドの識別情報を当該キューに入れる機能と、
第２のスレッドの処理において、前記キューへデータを入れる際、当該キューに前記第１のスレッドの識別情報が入っていなかったらデータを当該キューに入れ、当該キューに前記第１のスレッドの識別情報が入っていたら、当該第１のスレッドにデータを渡す機能と、
をコンピュータに実現させることを特徴とするコンピュータプログラム。
【発明の詳細な説明】
【技術分野】
【０００１】
本発明は情報処理技術に関し、具体的には複数のスレッドを処理する情報処理装置および情報処理方法に関する。
【背景技術】
【０００２】
近年の情報処理装置は、複数のプロセスを同時に実行することができるマルチタスク環境を実現するとともに、これらのプロセスがプロセス内部で複数のスレッドを生成して並行処理を行うことができるマルチスレッド技術を搭載している。プロセスは実行時に固有のリソースやアドレス空間が割り当てられ、他のプロセスの領域にアクセスすることができない。これに対してスレッドは、プロセス内部で生成される実行単位であり、各スレッドはプロセス内の領域に互いに自由にアクセスすることができる。スレッドは、オペレーティングシステムがＣＰＵ（Ｃｅｎｔｒａｌ  Ｐｒｏｃｅｓｓｉｎｇ  Ｕｎｉｔ）の実行時間を割り当てる基本的な実行単位となる。
【０００３】
このように複数のスレッドを並列に処理する環境においては、共有メモリ内にキューを設け、消費されるデータやリソースを要求するスレッドの待ち行列を生成できるようにすることで、プロセッサやスレッドの独立性を保持しつつ排他制御を実現することができる。
【発明の概要】
【発明が解決しようとする課題】
【０００４】
一般的に、あるスレッドがキューからデータを取り出そうとした際、キューにデータが存在しなければ、当該スレッドは、別のスレッドによって新たなデータが格納されるまでビジーループ状態となる。この間、ＣＰＵリソースは無駄に消費されることになるため、このような状態が発生するほど全体的な処理の効率が低下するという問題があった。
【０００５】
本発明はこのような課題に鑑みてなされたものであり、その目的は、スレッドによるキューへのアクセスに起因する処理効率の低下を防止することのできる情報処理技術を提供することにある。
【課題を解決するための手段】
【０００６】
本発明のある態様は情報処理装置に関する。この情報処理装置は、個々のデータの行列からなるデータ用キューを格納するメモリと、生成したデータをデータ用キューに入れるデータ生成スレッドと、データをデータ用キューから取り出すデータ消費スレッドと、の少なくともいずれかを処理する１つ以上のプロセッサと、を備え、プロセッサは、データ消費スレッドの処理において、データ用キューに取り出すべきデータが存在しない場合、当該データ用キューに、データ消費スレッドの識別情報を入れ、データ生成スレッドの処理において、データをデータ用キューに入れる際、当該データ用キューにデータ消費スレッドの識別情報が入っていたら、当該データ消費スレッドが取得できるようにデータの格納先を変更することを特徴とする。
【０００７】
本発明の別の態様は情報処理方法に関する。この情報処理方法は、プロセッサによる第１のスレッドの処理において、メモリに格納されたキューからのデータ取り出しを試みた際、取り出すべきデータが存在しない場合、第１のスレッドの識別情報を当該キューに入れるステップと、プロセッサによる第２のスレッドの処理において、前記キューへデータを入れる際、当該キューに第１のスレッドの識別情報が入っていたら、当該第１のスレッドにデータを渡すステップと、を含むことを特徴とする。
【０００８】
なお、以上の構成要素の任意の組合せ、本発明の表現を方法、装置、システム、コンピュータプログラム、コンピュータプログラムを記録した記録媒体などの間で変換したものもまた、本発明の態様として有効である。
【発明の効果】
【０００９】
本発明によると、排他制御に係る処理効率の低下が少ない情報処理を実現できる。
【図面の簡単な説明】
【００１０】
【図１】本実施の形態における情報処理装置の構成を示す図である。
【図２】本実施の形態におけるキューに格納する待ち行列のデータ構造例を模式的に示す図である。
【図３】本実施の形態において要素が入っていない状態のキューに要素をプッシュする操作の様子を示す図である。
【図４】本実施の形態において要素が格納されている状態のキューに新たな要素をプッシュする操作の様子を示す図である。
【図５】本実施の形態において複数の要素が格納されている状態のキューから要素をポップする操作の様子を示す図である。
【図６】本実施の形態においてひとつの要素のみが格納されている状態のキューから当該要素をポップする操作の様子を示す図である。
【図７】本実施の形態においてスレッドがキューを操作する手順を示すフローチャートである。
【図８】本実施の形態においてキューにポップするデータがない場合を考慮したときの基本的な処理手順を示すフローチャートである。
【図９】本実施の形態においてキューにポップするデータがない場合を考慮したときの基本的な処理手順を示すフローチャートである。
【図１０】本実施の形態においてデータのキューとパケットのキューの双方にスレッドの待ち行列を組み入れる場合の処理手順を示すフローチャートである。
【図１１】本実施の形態においてデータのキューとパケットのキューの双方にスレッドの待ち行列を組み入れる場合の処理手順を示すフローチャートである。
【図１２】本実施の形態においてセマフォの機能を実現するためにキューに格納するリンクリストの構造とその操作の様子を模式的に示す図である。
【図１３】本実施の形態において要求数に対して資源が足りない場合のリンクリストの操作の様子を示す図である。
【図１４】本実施の形態において資源獲得待ちをしているスレッドが存在する場合に資源を開放するときの、リンクリストの操作の様子を示す図である。
【図１５】本実施の形態において資源を要求する際の処理手順を示すフローチャートである。
【図１６】本実施の形態において資源を開放する際の処理手順を示すフローチャートである。
【図１７】本実施の形態において別のスレッドによってＷロックが獲得されている期間においてＲロックを要求するスレッドが発生した場合の、リンクリストの操作の様子を示す図である。
【図１８】本実施の形態においてＷロックを獲得していたスレッドがそれを解除するときのリンクリストの操作の様子を示す図である。
【発明を実施するための形態】
【００１１】
図１は本実施の形態における情報処理装置の構成を示している。情報処理装置１０は処理ユニット１２ａ、・・・、１２ｎと共有メモリ１４とを含み、それらはメインバス２０に接続されている。処理ユニット１２ａ、・・・、１２ｎはそれぞれ、プロセッサ１６ａ、・・・、１６ｎ、およびローカルメモリ１８ａ、・・・、１８ｎを含む。処理ユニット１２ａ、・・・、１２ｎはそれぞれプロセッサ１６ａ、・・・、１６ｎ、およびローカルメモリ１８ａ、・・・、１８ｎ以外の構成を含んでよいが、ここでは図示を省略している。
【００１２】
情報処理装置１０において各種機能を実現するために生成された複数のスレッドは、処理ユニット１２ａ、・・・、１２ｎにおいて並列に処理される。共有メモリ１４にはスレッドを処理するためのプログラムや各種データが格納され、プロセッサ１６ａ、・・・、１６ｎは、必要なデータを共有メモリ１４から自らの処理ユニットに属するローカルメモリ１８ａ、・・・、１８ｎに読み出したうえ、スレッド処理を開始する。
【００１３】
開始したスレッドに割り当てられたタイムスライスが満了した場合や、処理内容に応じて待機状態となった場合などに、プロセッサ１６ａ、・・・、１６ｎは処理対象を別のスレッドへ切り替える。なお以後の説明では、理解を容易にするため処理の主体を「スレッド」と表現する場合があるが、ハードウェア的には「スレッドを処理しているプロセッサ」を意味する。
【００１４】
スレッド処理の順序やＣＰＵ時間の割り当てを定めるスケジューリングは、ＯＳが提供するスケジューラによって行われてもよいし、ユーザレベルスケジューラによって行われてもよい。このようなスケジューリング処理も、一つのスレッドとしてプロセッサ１６ａ、・・・、１６ｎのいずれかが実行する。
【００１５】
本実施の形態では後述するように、キューの状態に応じて、処理中のスレッドがプロセッサを開放し待機状態になる場合と、別のスレッドの処理により待機状態となったスレッドの処理開始が可能となる場合がある。したがって、そのような場合にスレッドの状態移行を実現するプロセスをあらかじめ準備しておき、スレッドからの要求に従い実行されるようにしておく。このようなプロセスは、ＯＳによって提供されるものを利用してもよいし、ユーザレベルで準備してもよい。
【００１６】
共有メモリ１４はキュー２２を含む。キュー２２はデータやスレッドなどの待ち行列を格納する記憶領域である。後に詳述するように待ち行列の目的に対応させてキューを複数設けてよいが、ここではそれらを総括してキュー２２としている。図２は、本実施の形態におけるキュー２２に格納する待ち行列のデータ構造例を模式的に示している。
【００１７】
同図に示す待ち行列の目的は特に限定されず、スレッド処理の進行において必要な待ち行列であれば、待つ主体がスレッド自体であってもスレッド処理に必要なデータであってもよい。例えばあるスレッドが、イベントを発生させて当該イベントの識別情報をキュー２２に格納していき、別のスレッドが当該識別情報をキュー２２に格納された順に読み出し、それに基づきイベントを処理する場合が考えられる。この場合キュー２２には、処理を待つイベントの識別情報の待ち行列が形成される。
【００１８】
図２に示すように、本実施の形態の待ち行列はリンクリストの形態を有する。リンクリストは、複数のデータを、次のデータのアドレスへのポインタによって連結させた構造を有する。本実施の形態におけるリンクリスト２８は待ち行列を表すため、リンクする順番は、キュー２２に格納された順となる。上述したように目的によって待ち行列の主体は様々考えられるが、ここではそれらを総括して「要素」と呼ぶ。図２においてＥａ、Ｅｂ、Ｅｃはこの順で格納された要素を、Ｐｈ、Ｐａ、Ｐｂ、Ｐｔはポインタを表しており、各ポインタから出る矢印の先がポインタの示すアドレスに格納された要素となる。
【００１９】
まずポインタＰｈはヘッドポインタであり、最初に格納された要素Ｅａの格納先アドレスを示す。要素Ｅａと対応づけられたポインタＰａは、次に格納された要素Ｅｂの格納先アドレスを示す。要素Ｅｂと対応づけられたポインタＰｂは、その次に格納された要素Ｅｃの格納先アドレスを示す。ポインタＰｔはテイルポインタであり、図のように最後に格納された要素が要素Ｅｃであれば当該要素Ｅｃの格納先アドレスを示す。
【００２０】
このようなデータ構造によって、要素がいくつ格納されても、要素とその格納順を表すことができる。ＦＩＦＯ（First In, First Out)のポリシーで要素を待ち行列からはずす際は（以下、「ポップする」という）、まずヘッドポインタＰｈを参照し、待ち行列のうち最初に格納された要素Ｅａのアドレスを取得する。そして要素Ｅａを当該アドレスから読み出したあと、ヘッドポインタＰｈを次の要素Ｅｂの格納先アドレスに更新する。具体的には要素Ｅａに対応づけられていたポインタＰａの値をヘッドポインタＰｈにコピーする。
【００２１】
要素を待ち行列に追加する際は（以下、「プッシュする」という）、キュー２２の空き領域に当該要素を格納した後、テイルポインタＰｔを参照して、待ち行列の最後の要素Ｅｃのアドレスを取得する。そして当該要素Ｅｃに、追加する要素のアドレスを示す新たなポインタを対応づけるとともに、テイルポインタＰｔも当該アドレスに更新する。
【００２２】
リンクリストを用いるか否かに関わらず、キューなど複数のスレッドで共有する情報を操作する場合は一般的に、情報の整合性を保つためアクセスの排他制御が必要となる。この場合、ロックを獲得する、キューを操作する、ロックを解除する、という一連の処理を一つのスレッドが完了するまで、他のスレッドは、例え優先度が高くてもキューの操作を待たなければならない。
【００２３】
このように発生するキューへのアクセス待ち時間を削減するため、本実施の形態では、ロックせずに操作を行うノンブロッキングキューを実現する。具体的には、キューに対する一連の操作を複数のアトミック操作（不可分操作）で段階的に行い、アトミック操作の間では別のスレッドによるキュー操作の割り込みを許す。アトミック操作は他のスレッドによる干渉なしに実行されることが保証される操作である。そして割り込みにより中断された操作のうち残りの部分は、割り込んだスレッドが引き継ぐことにより完了させる。
【００２４】
図３〜６は、本実施の形態のノンブロッキングキューの操作手法をより詳細に説明するための図である。図３は要素が入っていない状態のキューに要素Ｅａをプッシュする操作の様子を示している。図の上から、状態５０、５２、５４、５６の順でキューの状態が変遷するとする。基本的な表示の仕方は図２のリンクリスト２８と同様であるが、ヘッドポインタＰｈ、テイルポインタＰｔ以外のポインタは矢印のみで表している。すなわち矢印の始点が各ポインタに対応づけられている要素、終点がポインタが示すアドレスに格納されている要素である。図４〜６も同様である。
【００２５】
まず状態５０はキューに要素が格納されていない初期状態を表している。このときリンクリストにはダミーの要素Ｅ＿ｄｕｍｍｙを入れておく。ダミーの要素Ｅ＿ｄｕｍｍｙは有効な要素でなく、あらかじめ所定のアドレスに準備しておく。このようにキューにダミーの要素Ｅ＿ｄｕｍｍｙを入れる場合、要素がダミーの要素Ｅ＿ｄｕｍｍｙであることを示す情報を、当該要素を示すポインタ、同図の例ではヘッドポインタＰｈに付加する。ポインタに別の情報を付加する手法は、後に図１２などを参照して詳述するのと同様である。あるいは、ポインタが示す先のアドレスにダミーであることを示す識別情報を格納することによってダミーの要素Ｅ＿ｄｕｍｍｙを識別してもよい。状態５０ではヘッドポインタＰｈおよびテイルポインタＰｔはどちらも、ダミーの要素Ｅ＿ｄｕｍｍｙのアドレスを示している。この状態からあるスレッドが要素Ｅａをプッシュする場合、まず要素Ｅａを空いている記憶領域に格納しておく。そして当該記憶領域のアドレスを示すポインタを、ダミーの要素Ｅ＿ｄｕｍｍｙに対応づけることにより状態５２とする（第１操作）。
【００２６】
次にテイルポインタＰｔを、要素Ｅａを格納した記憶領域のアドレスを示すように更新して状態５４とする（第２操作）。次にヘッドポインタＰｈを、第１操作においてダミーの要素Ｅ＿ｄｕｍｍｙに対応づけたポインタの値に更新することにより、ヘッドポインタＰｈが要素Ｅａのアドレスを示す状態５６とする（第３操作）。以上の手順により、キューに最初の要素をプッシュ処理が完了する。本実施の形態では、このように段階を追ってポインタの更新を行う。そして第１操作、第２操作、第３操作をそれぞれアトミック操作とする。
【００２７】
図４は要素Ｅａ、Ｅｂが格納されている状態のキューに新たな要素Ｅｃをプッシュする操作の様子を示している。まず状態６０では、ヘッドポインタＰｈが最初に格納された要素Ｅａのアドレスを、要素Ｅａに対応づけられたポインタおよびテイルポインタが、要素Ｅａの次に格納され、かつ最後に格納された要素Ｅｂのアドレスを示している。
【００２８】
この状態６０からあるスレッドが要素Ｅｃをプッシュする場合、まず要素Ｅｃを空いている記憶領域に格納しておく。そして当該記憶領域のアドレスを示すポインタを、要素Ｅｂに対応づけることにより状態６２とする（第１操作）。次にテイルポインタＰｔを、要素Ｅｃを格納した記憶領域のアドレスを示すように更新して状態６４とする（第２操作）。以上の手順により、元から要素が入っているキューに新たな要素をプッシュ処理が完了する。このときもポインタの更新は段階的に実施し、第１操作、第２操作をアトミック操作とする。
【００２９】
図５は複数の要素Ｅａ、Ｅｂが格納されている状態のキューから要素Ｅａをポップする操作の様子を示している。状態７０は図４の状態６０と同様である。この状態７０からあるスレッドが最初に格納された要素Ｅａをポップする場合は、まずヘッドポインタＰｈを参照して要素Ｅａのアドレスを取得し、当該アドレスに格納された要素Ｅａをローカルメモリ１８ａなどに読み出しておく。そしてヘッドポインタＰｈを、読み出した要素Ｅａに対応付けられていたポインタの値に更新することにより状態７２とする（第１操作）。以上の手順により、要素が複数入っているキューから最初に格納された要素をポップする処理が完了する。このときのキューに対する操作、すなわち第１操作をアトミック操作とする。
【００３０】
図６は要素Ｅａのみが格納されている状態のキューから当該要素Ｅａをポップする操作の様子を示している。まず状態８０では、ヘッドポインタＰｈおよびテイルポインタＰｔが唯一の要素である要素Ｅａのアドレスを示している。この状態からあるスレッドが要素Ｅａをポップする場合、ヘッドポインタＰｈとテイルポインタＰｔが同じアドレスを示していることから要素Ｅａがキューにおける最後の要素であること、ダミーの要素Ｅ＿ｄｕｍｍｙがキューに含まれていないこと、を判断すると、まずダミーの要素Ｅ＿ｄｕｍｍｙを所定の記憶領域に格納するなどダミーの要素Ｅ＿ｄｕｍｍｙに対して必要な初期化を行い状態８２とする（第１操作）。
【００３１】
そしてダミーの要素Ｅ＿ｄｕｍｍｙのアドレスを示すポインタを、要素Ｅａに対応づけることにより状態８４とする（第２操作）。次にテイルポインタＰｔを、ダミーの要素Ｅ＿ｄｕｍｍｙのアドレスを示すように更新して状態８６とする（第３操作）。次にヘッドポインタＰｈを参照して要素Ｅａのアドレスを取得し、ヘッドポインタＰｈを要素Ｅａに対応付けられていたポインタの値、すなわち要素Ｅ＿ｄｕｍｍｙのアドレスに更新することにより状態８８とする（第４操作）。
【００３２】
このとき要素Ｅａをローカルメモリ１８ａなどに読み出しておく。以上の手順により、キューから最後の要素をポップする処理が完了する。これまで同様、第１操作、第２操作、第３操作、第４操作はそれぞれアトミック操作とする。
【００３３】
図３〜６にそれぞれ示した一連の操作のいずれかによって、キューに対する操作を全て実現することができる。ここでキューはロックされていないため、アトミック操作の間の期間、すなわち図３の状態５２、５４、図４の状態６０、図６の状態８２、８４、８６で別のスレッドによるキュー操作の割り込みが発生する可能性がある。このときは、ある条件において、割り込んだスレッドが、自らが目的とする操作を開始する前に、割り込みによって中断された操作のうち残りの操作を引き継ぐ。
【００３４】
次にキュー操作の引継ぎを実現するためのスレッドの動作を説明する。図７はスレッドがキューを操作する手順を示すフローチャートである。図７〜１１、図１５、１６に示すフローチャートにおいては、各部の処理手順を、ステップを意味するＳ（Ｓｔｅｐの頭文字）と数字との組み合わせによって表示する。また、Ｓと数字との組み合わせによって表示した処理で何らかの判断処理が実行され、その判断結果が肯定的であった場合は、Ｙ（Ｙｅｓの頭文字）を付加して、例えば、（Ｓ１０のＹ）と表示し、逆にその判断結果が否定的であった場合は、Ｎ（Ｎｏの頭文字）を付加して、（Ｓ１０のＮ）と表示する。
【００３５】
図７のフローチャートにおける処理は、あるスレッドがキューへアクセスしたときに開始する。まずスレッドが要素のポップまたはプッシュを目的にキューへアクセスする（Ｓ１０）。そして図３〜６のいずれかの操作を試みる。例えば、プッシュの場合は図３の状態５０あるいは図４の状態６０の状態にあれば、ポップの場合は図５の状態７０あるいは図６の状態８０の状態にあれば、操作が可能である。この場合は（Ｓ１２のＹ）、同スレッドの本来の目的である操作を実行する（Ｓ１６）。状態５０、６０、７０、８０になくても、可能であれば操作を実行する。
【００３６】
例えば図６の状態８４のようにテイルポインタＰｔが最後の要素のアドレスを示していない場合を考える。このような状態でも要素のポップは可能である。なぜなら要素のポップはヘッドポインタＰｈが示すアドレスのみ参照することによって実行可能なためである。一方、要素のプッシュは、図４で説明したとおり、テイルポインタＰｔが示す最後尾の要素に、プッシュする要素のアドレスを示す新たなポインタを対応づける第１操作が必要である。そのため状態８４のように、テイルポインタＰｔが最後尾の要素以外のアドレスを示している場合、当該要素にはすでに別の要素へのポインタが対応づけられているため、第１操作ができない。
【００３７】
このように、本来の目的である操作ができない場合は（Ｓ１２のＮ）、その前にキューを操作していた別のスレッドの操作が完了していないと判断し、残された操作を実行する（Ｓ１４）。例えば上述のようにテイルポインタＰｔが最後尾の要素のアドレスを示していない場合は、テイルポインタＰｔが示している要素からリンクを辿り最後尾の要素を特定し、そのアドレスをもってテイルポインタＰｔを更新する。本来の操作を妨げる不正な状態のバリエーションと、各状態に対してＳ１４で実行すべき操作とは、あらかじめ対応づけて共有メモリ１４に格納しておき、必要に応じて参照する。
【００３８】
そして再度、本来の目的である操作を試みる（Ｓ１２）。操作ができなければ、さらに、そのときの不正な状態に対応する操作を実行する（Ｓ１２のＮ、Ｓ１４）。これらの処理を、本来の目的である操作が可能になるまで繰り返すことにより、実質的に、前のスレッドが残した操作を引き継いだことになる。そのうえで本来の操作を実行する（Ｓ１２のＹ、Ｓ１６）。
【００３９】
なお図６の第３操作が終わった状態８６において別のスレッドが要素のポップを目的に割り込みを行った場合は、前のスレッドの残りの操作、すなわち要素Ｅａのポップが、割り込みを行ったスレッドが目的とする操作と一致するため、現スレッドの本来の操作として実行する。この場合、割り込まれたスレッドは次にキューへアクセスした際、要素をポップするための最初の操作、すなわち図６の第１操作から実施する。このときキューにダミーの要素Ｅ＿ｄｕｍｍｙしかなければ、エラーとして操作を終了する。
【００４０】
以上述べたように本実施の形態では、キューに対するロックはせずに、一連の操作を複数のアトミック操作で多段階に実施する。これにより、スレッドがキューへのアクセスを待機する状態が発生しなくなり情報処理装置全体として処理効率が向上する。また、キューへのアクセスを割り込んだスレッドは、前のスレッドが行っていた操作のうち残りの操作を引き継ぐことにより、割り込みによってキューに一時的に不正な状態が生じてもその都度修正することができ、キューの整合性が保たれる。
【００４１】
次に、これまで述べたノンブロッキングキューを利用して、さらに処理効率を上げる様々な態様を説明する。
【００４２】
（１）データ待ちのスレッドを考慮したキュー
キューに格納された全てのデータが読み出し済みの場合など、あるスレッドがデータのポップを目的にキューにアクセスしてもデータが格納されていない場合がある。このような場合、一般的にはデータがキューに格納されるまでビジーループの状態となり、ＣＰＵリソースを無駄に消費する。本実施の形態では上述したノンブロッキングキューの説明における「要素」として、スレッドの処理に用いる「データ」と、スレッドの識別情報などの「スレッド情報」を一つのキューに混在させることにより、データの不在とスレッドの待ち状態とを直結させて処理を効率化する。
【００４３】
この場合も情報処理装置の構成は図１で説明したのと同様でよい。またノンブロッキングキューを利用するため、キューに対する操作は、図３〜７で説明したのと同様でよい。図８および図９は、キューにポップするデータがない場合を考慮したときの基本的な処理手順を示すフローチャートである。図８はデータをポップしたい場合のフローチャートであり、この処理は、スレッドがデータをポップするためにキューにアクセスしたときに開始される。
【００４４】
スレッドはまず、アクセスしたキューにポップできるデータあるか否かを確認し、データがあればそれをポップする（Ｓ２２のＹ、Ｓ２４）。一方、データがなかった場合、スレッドは、自らのスレッドの識別情報を含むスレッド情報を同じキューにプッシュしたうえ、プロセッサを開放し待機状態へ移行する（Ｓ２２のＮ、Ｓ２８、Ｓ３０）。すなわちポップするデータがない場合にスレッドは、キューに対する操作をスレッド情報のプッシュに切り替えたうえ、待機状態へ移行する。このときキューにはスレッド情報が格納されることになる。このときさらに、プッシュしたスレッド情報を示すヘッドポインタに、スレッド情報が格納されていることを示す情報を付加しておいてもよい。なおＳ２２においては、キューにダミーの要素またはスレッド情報のみが格納されている場合に、当該キューにはデータがない、と判断する（Ｓ２２のＮ）。
【００４５】
図９はデータをプッシュしたい場合のフローチャートであり、この処理は、スレッドがデータをプッシュするためにキューにアクセスしたときに開始される。この場合、スレッドはまず、アクセスしたキューにスレッド情報があるか否かを確認し、スレッド情報がなければそのままデータをプッシュすることにより目的を遂げる（Ｓ３２のＹ、Ｓ３４）。一方、スレッド情報があれば、データを待っているスレッドがあると判断し、当該スレッド情報をポップしたうえ、それに基づき特定したスレッドに直接データを渡す（Ｓ３２のＮ、Ｓ３６、Ｓ３８）。スレッド情報をプッシュした際、スレッド情報が格納されていることを示す情報をヘッドポインタに付加する態様においては、ヘッドポインタを参照することによりＳ３２の判定を行う。
【００４６】
Ｓ３８の処理は実際には、データをプッシュしようとしたスレッドが、データを渡すべきスレッドに割り当てられた共有メモリ１４内の領域へ当該データを格納したうえ、スレッド処理を開始させるプロセスに、ポップしたスレッド情報を渡すことにより、当該スレッドの処理を再開させる。このようにデータのプッシュにおいても、キューにスレッド情報が格納されている場合は当該スレッド情報のポップに操作を切り替える。
【００４７】
このような処理によって、一つのキューにおいて、データの待ち行列とスレッドの待ち行列を同時に管理することができる。データの不在とスレッドの待機状態とを直結させて、アトミックに双方を操作できるため、管理のための処理に要する時間を短縮できる。またデータがない場合にスレッドがビジーループにならずにプロセッサを即座に開放できるため、情報処理装置全体として処理効率が向上する。
【００４８】
図８、９はスレッド処理に必要なデータのキューにスレッドの待ち行列を組み入れる処理手順であったが、本手法はデータのキュー以外にも適用できる。例えばデータをキューにプッシュする際に必要となる空きパケットのキューに対して同様の操作を行うようにしてもよい。ここでパケットは、データを格納する所定単位の記憶領域をデータの入れ物として実体化したものであり、使用可能なパケット数をあらかじめ定めておくことにより、共有メモリのうちキューのために使用可能な領域を制限できる。パケットの概念は、ネットワークを介した通信などにおいて広く導入されている。
【００４９】
図１０、１１は、データのキューと空きパケットのキューの双方にスレッドの待ち行列を組み入れる場合の処理手順を示すフローチャートである。この場合、空きパケットのキューとして、データを格納するためのデータ用空きパケットのキュー、スレッド情報を格納するためのスレッド情報用空きパケットのキューを設ける。それらのキューのいずれも、ノンブロッキングキューで構成する。
【００５０】
データ用空きパケットのキュー、スレッド情報用空きパケットのキューは、パケットとして区切られた共有メモリの各領域のうち、読み出し前のデータまたはスレッド情報が格納されていない領域、すなわち空きパケットのアドレスを示すキューである。それに対しデータのキューは、読み出し前のデータまたはスレッド情報が格納されている領域のアドレスを示すキューである。
【００５１】
例えばデータ用空きパケットのキューからデータ用空きパケットをポップし、それにデータを入れてデータのキューにプッシュする、という一連の処理は、実際には、データ用空きパケットのキューから空いている記憶領域へのポインタを取得して新たなデータを書き込み、当該領域へのポインタをデータのキューに加える処理となる。逆に、データのキューからデータをポップして不要になった空きパケットをデータ用空きパケットのキューへプッシュする、という一連の処理は、実際には、データのキューのポインタが示す領域のデータを読み出し、当該領域へのポインタをデータ用空きパケットのキューに加える処理となる。スレッド情報についても同様である。
【００５２】
図１０はキューからデータをポップしたい場合の処理手順を示すフローチャートであり、その処理は、スレッド処理においてデータをポップする必要が生じたときに開始される。まずスレッドは、スレッド情報用空きパケットのキューからスレッド情報用空きパケットを確保する（Ｓ４０）。次にデータのキューにアクセスし、ポップ処理を行う（Ｓ４２）。このとき図８で説明したように、ポップできるデータがあればポップし、なければスレッド情報をプッシュする。スレッド情報をプッシュする場合は、Ｓ４０で確保したスレッド情報用空きパケットにスレッド情報を格納したうえでデータのキューに格納する。
【００５３】
Ｓ４２でデータをポップできずにスレッド情報をプッシュした場合は、当該スレッドは待機状態となるためデータのポップ処理を一旦終える（Ｓ４４のＮ）。一方、データをポップできた場合は（Ｓ４４のＹ）、不要となったスレッド情報用空きパケットをスレッド情報用空きパケットのキューに返却する（Ｓ４６）。この処理は実際にはスレッド情報用空きパケットのキューへのプッシュとなる。
【００５４】
さらにポップしてローカルメモリなどに読み出し終わったデータが入っていたデータ用空きパケットを返却するため、データ用空きパケットキューへアクセスし、プッシュ処理を行う（Ｓ４８）。この処理は、図９のフローチャートにおける「データ」を「データ用空きパケット」に置き換えることにより同じ処理手順で実現できる。すなわちデータ用空きパケットキューにスレッド情報があればそれをポップして当該スレッドにデータ用空きパケットを直接渡し、なければデータ用空きパケットをプッシュする。
【００５５】
図１１はキューにデータをプッシュしたい場合の処理手順を示すフローチャートであり、その処理は、スレッド処理においてデータをプッシュする必要が生じたときに開始される。まずスレッドは、スレッド情報用空きパケットのキューからスレッド情報用空きパケットを確保する（Ｓ５０）。次にデータ用空きパケットのキューにアクセスし、データ用空きパケットのポップ処理を行う（Ｓ５２）。
【００５６】
この処理は、図８のフローチャートにおける「データ」を「データ用空きパケット」に置き換えることにより同じ処理手順で実現できる。すなわちデータ用空きパケットがあればポップし、なければスレッド情報をプッシュする。スレッド情報をプッシュする場合は、Ｓ５０で確保したスレッド情報用空きパケットにスレッド情報を格納したうえでデータ用空きパケットのキューに格納する。
【００５７】
Ｓ５２でデータ用空きパケットをポップできずにスレッド情報をプッシュした場合は、当該スレッドは待機状態となるためデータのプッシュ処理を一旦終える（Ｓ５４のＮ）。一方、データ用空きパケットをポップできた場合は（Ｓ５４のＹ）、不要となったスレッド情報用空きパケットをスレッド情報用空きパケットのキューに返却する（Ｓ５６）。この処理は実際にはスレッド情報用空きパケットのキューへのプッシュとなる。
【００５８】
さらにデータのキューにアクセスし、Ｓ５２でポップしたデータ用空きパケットを用いて、データのプッシュ処理を行う（Ｓ５８）。このとき図９で説明したように、データ用空きパケットキューにスレッド情報があればそれをポップして当該スレッドにデータを直接渡し、なければデータをプッシュする。
【００５９】
このような構成とすることで、スレッド処理に必要なデータのポップ、プッシュのみならず、その前後の処理として必要な空きパケットの確保、返却の処理においても、キューのアクセス待ちによってスレッドがビジーループの状態とならずにプロセッサを開放することができる。各キューはノンブロッキングであることから、空きパケット獲得処理、データ読み出し処理の双方で、キューへのアクセス待ちによるスレッドの待ち時間を減らすことができる。
【００６０】
（２）セマフォ
セマフォは、複数のスレッドで共通して利用する資源について、資源使用の同期をとる手法として広く用いられている。具体的には、利用可能な資源数を表すカウンタを共有メモリに用意し、資源を利用する場合は利用する数だけカウンタの値を減らし、資源を利用し終えて開放する場合はその数だけカウンタ値を増やす。例えばデバイスやメモリなどへのアクセス権を資源とした場合、同時にアクセスすることのできるスレッド数の上限をカウンタの初期値とし、カウンタの値を整数に限れば、アクセス数が上限に達したときにカウンタが０になり、それ以上のアクセスはできなくなる。
【００６１】
ここでは、ノンブロッキングキューの構成を利用して、セマフォの機能を効率的に実現する手法を説明する。図１２はセマフォの機能を実現するためにキュー２２に格納するリンクリストの構造とその操作の様子を模式的に示している。リンクリストの構造やキューに対する基本的な操作はこれまで説明したのと同様であるが、セマフォを実現する場合は、リンクリストのポインタに資源数に係る情報を付加する。同図において、状態９０のヘッドポインタＰｈには現在利用可能な資源数を表すカウンタ値Ｎｒが付加されている。
【００６２】
どのスレッドも当該資源を利用していない場合、カウンタ値Ｎｒはあらかじめ設定した上限値となる。本実施の形態では以下に述べるように、セマフォの機構に、資源を獲得するためのスレッドの待ち行列を組み入れる。そのため、カウンタ値Ｎｒは整数に限定せず、資源の数が足りない場合を負の値で表現する。要求される資源数も負の値で表現する。
【００６３】
状態９０からあるスレッドが資源を要求する場合は、まずヘッドポインタＰｈを参照し、それに付加されているカウンタ値Ｎｒを取得する。そして資源の要求数がカウンタ値Ｎｒ以下であれば要求した数の資源を獲得できるため、元のカウンタ値Ｎｒから要求数を減算してカウンタ値を更新する（同図では「Ｎｒ’」としている）。この第１操作により状態９２となり、要求数に対して資源数が足りているときの資源の獲得が完了する。
【００６４】
ここでの第１操作もアトミック操作とする。そのためカウンタ値Ｎｒは、ポインタと合わせてアトミック操作が可能なデータサイズとする。例えばアトミック操作を実施できるデータサイズが４バイト単位であったら、３バイトをポインタに、１バイトをカウンタ値Ｎｒに割り当てる。サイズが足りない場合は、例えばポインタをインデックス構造としてリンクリストの操作時はポインタのインデックスのみを操作し、データアクセスが必要なときのみ実際のアドレスを引くようにしてもよい。なお状態９０からあるスレッドが資源を開放する場合は、カウンタ値Ｎｒに開放する資源数を加算して更新すればよい。
【００６５】
図１３は要求数に対して資源が足りない場合のリンクリストの操作の様子を示している。ここでは理解を容易にするため、カウンタ値や要求数を具体的な数値例で示している。まず状態１００において、ヘッドポインタＰｈに付加されたカウンタ値Ｎｒは「５」となっており、５個の資源が利用可能であることを表している。この状態１００からあるスレッドが、資源数１０を要求するとする。この場合、当該スレッドはヘッドポインタＰｈに付加されているカウンタ値「５」を参照し、要求数より小さいと判断すると、キューに対し自らのスレッド情報をプッシュする操作を開始する。
【００６６】
このとき、まずスレッド情報を空いている記憶領域に格納する。そして当該記憶領域のアドレスを示すポインタに、資源の要求数を負の値として付加し、ダミーの要素Ｅ＿ｄｕｍｍｙに対応づけることにより、状態１０２とする（第１操作）。状態１０２などにおいて、ヘッドポインタＰｈ、テイルポインタＰｔ以外のポインタを表す矢印上に示した数値が、当該ポインタに付加された資源要求数である。この例では資源数１０を要求しているため「−１０」がポインタに付加される。このように、ヘッドポインタＰｈ以外のポインタに付加する情報は、当該ポインタが示す、次のスレッドが要求する資源の数とする。
【００６７】
次にテイルポインタＰｔを、プッシュしたスレッド情報のアドレスを示すように更新して状態１０４とする（第２操作）。次にヘッドポインタＰｈを、ダミーの要素Ｅ＿ｄｕｍｍｙに対応づけられたポインタの値に更新することにより、ヘッドポインタＰｈがスレッド情報のアドレスを示す状態とする。このとき同時に、ヘッドポインタＰｈに付加されていたカウンタ値に、ダミーの要素Ｅ＿ｄｕｍｍｙに対応づけられたポインタに付加されていた資源の要求数を加算し、更新後のヘッドポインタＰｈに付加する。同図においては５−１０＝−５がヘッドポインタＰｈに付加されている。
【００６８】
これらの第３操作により状態１０６となる。このようにヘッドポインタＰｈに付加されているカウンタ値Ｎｒは、負の値のときは資源の不足数を表す。この場合、資源獲得待ちをしているスレッドの待ち行列が形成される。状態１０６からさらに別のスレッドが資源を要求する場合は、そのスレッド情報をプッシュし、追加したスレッド情報を示すポインタには当該スレッドの資源要求数を付加する。なおこれまで同様、第１操作、第２操作、第３操作はそれぞれアトミックに実施する。
【００６９】
図１４は資源獲得待ちをしているスレッドが存在する場合に資源を開放するときの、リンクリストの操作の様子を示している。同図において状態１０８では、２つのスレッドが資源獲得待ちをしており、それぞれのスレッド情報、すなわちスレッド情報ａ、スレッド情報ｂがこの順でキューに格納されている。待ち行列の最初のスレッドが要求している資源数に対する不足分は、ヘッドポインタＰｈに付加されいるカウンタ値で表され、この場合は「−５」である。スレッド情報ｂに対応する、待ち行列の次のスレッドの資源要求数は、スレッド情報ａに対応づけたポインタに付加されている。同図では「−２」が付加されている。
【００７０】
この状態１０８に対し、あるスレッドが資源数６を開放するとする。この場合、当該スレッドはまずヘッドポインタＰｈに付加されているカウンタ値を参照し、それが負の値であることから、資源獲得待ちのスレッドがあると判断する。そして当該カウンタ値に、開放する資源数を加算して新たなカウンタ値とする。この値が０以上であれば、待ち行列の最初のスレッドは要求した資源数を獲得できるため、対応するスレッド情報ａをポップすることにより待ち行列からはずす。この例では開放する資源数が「６」、カウンタ値が「−５」で、新たなカウンタ値は「１」となることから、スレッド情報ａをポップする。
【００７１】
その際、ヘッドポインタＰｈを、ポップしたスレッド情報ａに対応付けられていたポインタの値に更新するとともに、当該ポインタに付加されていた、次のスレッドの資源要求数を、先に算出した新たなカウンタ値にさらに加算し、ヘッドポインタＰｈに付加する。同図の例では最初のスレッドが資源を獲得した直後のカウンタ値が上記のとおり「１」であり、次のスレッドの要求数が「−２」であるため、１−２＝−１のカウンタ値をヘッドポインタＰｈに付加する。これらの第１操作によってスレッド情報ａがポップされた状態１１０となる。
【００７２】
この例のようにカウンタ値が負であれば、ヘッドポインタＰｈが示すスレッドの資源要求数に対して利用できる資源が不足しているため、次に資源が開放されるまでそれ以上のスレッド情報はポップしない。一方、状態１１０においてカウンタ値が正であった場合は、次に資源獲得待ちをしていたスレッドも要求した資源を獲得できるため、スレッド情報を続けてポップする。ポップしたスレッド情報を、スレッド処理を開始させるプロセスに与えることにより、獲得した資源を用いてスレッドの処理が再開される。待ち行列にあった最後のスレッド情報をポップする際は、図６と同様にダミーの要素をプッシュする。
【００７３】
図１５は資源を要求する際の処理手順を示すフローチャートである。このフローチャートにおける処理は、資源を要求するスレッドがキューにアクセスしたときに開始される。まずスレッドは、ヘッドポインタＰｈに付加されたカウンタ値を参照し、要求数に対して利用できる資源数が足りているかを判断する（Ｓ６０）。足りている場合は（Ｓ６０のＹ）、要求数だけ減算することによりカウンタ値を更新し、要求した資源を獲得する（Ｓ６２）。
【００７４】
利用可能な資源数が足りない場合は（Ｓ６０のＮ）、自らのスレッド情報をキューにプッシュする（Ｓ６４）。そして要求数だけ減算することによりカウンタ値を更新する（Ｓ６６）。このときのカウンタ値は負の値となる。その後、当該スレッドはプロセッサを開放し待機状態へ移行する（Ｓ６８）。
【００７５】
図１６は資源を開放する際の処理手順を示すフローチャートである。このフローチャートにおける処理は、資源を開放するスレッドがキューにアクセスしたときに開始される。まずスレッドは、ヘッドポインタＰｈに付加されたカウンタ値が負であるかを確認することにより、資源獲得待ちのスレッドがあるか否かを判断する（Ｓ７０）。資源獲得待ちのスレッドがない場合は（Ｓ７０のＮ）、開放する資源数を加算することによりカウンタ値を更新して開放処理を終える（Ｓ７２）。
【００７６】
資源獲得待ちのスレッドがある場合は（Ｓ７０のＹ）、待ち行列の最初のスレッドが要求する資源の不足分が、開放する資源数で足りるか否かを判定する（Ｓ７４）。上述したように、元のカウンタ値に開放する資源数を加算した新たなカウンタ値が０以上であれば資源数が足りていると判定できる。開放する資源数で足りる場合は（Ｓ７４のＹ）、当該スレッドのスレッド情報をポップして待ち行列からはずし（Ｓ７６）、獲得した資源を用いて当該スレッドの処理を再開させる（Ｓ７８）。
【００７７】
待ち行列に後続のスレッドがある場合で（Ｓ７０のＹ）、その資源要求数に対し開放する資源の残りで足りる場合は（Ｓ７４のＹ）、順次スレッド情報のポップとスレッド処理の再開を実施する（Ｓ７６、Ｓ７８）。資源獲得待ちスレッドがなくなったり（Ｓ７０のＮ）、開放する資源数では足りなくなった場合は（Ｓ７４のＮ）、その時のカウンタ値をその時点における最終的なカウンタ値としてヘッドポインタＰｈに付加し、開放処理を終了する（Ｓ７２）。
【００７８】
このような構成とすることで、セマフォの機能と資源獲得待ちスレッドのキューの機能を同時に実現することができる。これらの機能は同じキューに対するアトミック操作で可能になることから、資源が足りない場合に資源要求元のスレッドを即座に待機状態としてプロセッサを開放することができる。また資源を獲得できる状態となったら待機状態となっていたスレッドの処理を即座に再開させることができる。これらの処理はノンブロッキングで行われることから、キューへのアクセス、資源の要求および開放、スレッドの待機および処理の再開といった各ステップにおいてスレッドの待ち時間を減らすことができる。
【００７９】
（３）ＲＷロック
共有メモリに格納されたデータに対する、複数のスレッドによるアクセス制御の手法として、Ｒ（Reader）ロックおよびＷ（Writer）ロックがある。一般に、あるスレッドがデータを読み出すためにＲロックを獲得している期間は、他のスレッドもＲロックを獲得でき、複数のスレッドが同時に読み出しを行えるようにする。一方、あるスレッドがデータを書き込むためにＷロックを獲得している期間は、他のスレッドは当該データへアクセスできないようにする。このようにすることでデータの整合性を保障する。
【００８０】
ＲロックとＷロックは同時には発生せず、例えば書き込みを行いたいスレッドは、別のスレッドが獲得したＲロックが解除されるまで待ち、Ｗロックを獲得してから書き込みを行う。読み出しを行いたいスレッドは、すでに別のスレッドがＲロックを獲得していれば、自らもＲロックを獲得し読み出しを開始する。一方、別のスレッドがＷロックを獲得している場合はそれが解除されるまで待ち、Ｒロックを獲得してから読み出しを行う。
【００８１】
ここでは、ノンブロッキングキューの構成を利用してＲＷロックの管理を効率的に実現する手法を説明する。この場合もセマフォについて上述したのと同様、ＲＷロックの管理機構に、ロックを獲得するためのスレッドの待ち行列を組み入れる。そのためリンクリストのポインタには、ＲＷロックの情報を付加する。ここでＲＷロックの情報は、現在のロックの状態およびロック獲得待ちをしているスレッドが要求しているロックの種別の情報を含む。
【００８２】
現在のロックの状態とは、Ｒロックを獲得しているスレッド数とＷロックを獲得しているスレッド数である。以後の説明では前者を変数Ｒ、後者を変数Ｗで表す。上述のとおり変数Ｗの最大値は１であり、変数Ｒは特に上限を設けない。また変数Ｒが０以外の値をとるとき変数Ｗは０、変数Ｗが１のとき変数Ｒは０である。リンクリストの構造とその操作の様子は基本的にはセマフォに関して説明したのと同様である。
【００８３】
例えばロック獲得待ちのスレッドがない状態では、図１２におけるカウンタ値Ｎｒの代わりに、現在のロックの状態がヘッドポインタＰｈに付加される。一方、ロック獲得待ちのスレッドがある場合は、ヘッドポインタＰｈにはさらに、リンクリストの最初のスレッドが要求するロックの種別、すなわちＲロックかＷロックかを示す情報が付加される。
【００８４】
Ｒ＝０、Ｗ＝０、すなわちどのスレッドもロックを獲得していない状態では、スレッドはどちらのロックであってもすぐに獲得できる。具体的には、スレッドはまずヘッドポインタＰｈを参照し、それに付加されている現在のロックの状態を取得する。上記のようにＲ＝０、Ｗ＝０である場合、スレッドは自らが要求するロックの種別に応じて変数Ｒまたは変数ＷをインクリメントすることによりＲロックまたはＷロックを獲得する。Ｒが０以外の値であった場合でも、スレッドがＲロックを要求する場合は変数ＲをインクリメントすることによりＲロックを獲得できる。
【００８５】
図１７は、別のスレッドによってＷロックが獲得されている期間においてＲロックを要求するスレッドが発生した場合の、リンクリストの操作の様子を示している。同図では理解を容易にするため、ＲＷロックの情報を具体例で示している。まず状態１２０において、ヘッドポインタＰｈに付加されたＲＷロックの情報は、「Ｒ＝０，Ｗ＝１」となっており、別のスレッドがＷロックを獲得していることを表している。Ｒロックを要求するスレッドはまず、ヘッドポインタＰｈに付加されているＲＷロックの情報を参照してＷロックが獲得されていることを確認すると、キューに対し自らのスレッド情報をプッシュする。
【００８６】
このとき、まずスレッド情報を空いている記憶領域に格納し、当該記憶領域のアドレスを示すポインタに、要求するロックの種別を表す識別情報、同図では「Ｒロック」を付加し、ダミーの要素Ｅ＿ｄｕｍｍｙに対応づけることにより状態１２２とする（第１操作）。次にテイルポインタＰｔを、当該スレッド情報のアドレスを示すように更新して状態１２４とする（第２操作）。次にヘッドポインタＰｈを、ダミーの要素Ｅ＿ｄｕｍｍｙに対応づけられたポインタの値に更新することにより、ヘッドポインタＰｈがスレッド情報のアドレスを示す状態とする。
【００８７】
このとき同時に、ダミーの要素Ｅ＿ｄｕｍｍｙに対応づけられたポインタに付加されていた、待ちスレッドが要求するロックの種別を表す識別情報「Ｒロック」をヘッドポインタＰｈの付加情報に追加する。これらの第３操作により状態１２６となる。結果的にヘッドポインタＰｈには、現在のロックの状態を示す情報と、ヘッドポインタＰｈが示すスレッドが要求するロックの種別とが付加されることになる。
【００８８】
状態１２６からさらに別のスレッドがＲロックまたはＷロックを要求した場合、そのスレッド情報をプッシュし、追加したスレッド情報を示すポインタには、当該スレッドが要求するロックの種別を付加する。なおこれまで同様、第１操作、第２操作、第３操作はそれぞれアトミックに実施する。そのためセマフォに関して説明したように、ポインタに付加するＲＷロックの情報は、ポインタと合わせてアトミック操作が可能なデータサイズとする。同図は最初にＷロックが獲得されている場合を示したが、最初にＲロックが獲得されている状態でＷロックを要求する場合も同様の操作となる。
【００８９】
図１８は、Ｗロックを獲得していたスレッドがそれを解除するときのリンクリストの操作の様子を示している。同図において状態１３０では、Ｒロックを要求しているスレッドとＷロックを要求しているスレッドがこの順で待ち行列を形成しており、それぞれのスレッド情報、すなわちスレッド情報ａ、スレッド情報ｂがこの順でキューに格納されている。ここでＷロックを解除するスレッドはまず、ヘッドポインタＰｈに付加されているＲＷロックの情報を参照し、要求されるロックの種別を表す識別情報が含まれていることから、ロック獲得待ちのスレッドがあると判断する。
【００９０】
そしてリンクリストの待ち行列のうち最初のスレッド情報ａをポップする。このときヘッドポインタＰｈを、ポップしたスレッド情報ａに対応付けられていたポインタの値に更新するとともに、ヘッドポインタＰｈに付加したＲＷロックの情報を更新する。同図の場合、Ｗロックを解除するので変数Ｗをデクリメントし、ポップしたスレッド情報ａに対応するスレッドにＲロックを獲得させるため変数Ｒをインクリメントする。さらに後続のスレッド情報ｂに対応するスレッドがＷロックを要求しているため、ヘッドポインタＰｈに付加するＲＷロックの情報において「Ｒロック」を「Ｗロック」に書き換える。これにより状態１３２となる。
【００９１】
ここで後続のスレッド情報ｂに対応するスレッドがＲロックを要求していた場合は、続けてＲロックを獲得させることができるため、スレッド情報ｂもポップする。このように自らのロックを解除するスレッドは、他にロック獲得待ちのスレッドがある場合、待ち行列の最初のスレッド情報をポップして、対応するスレッドにロックを獲得させる。獲得させたロックがＲロックであった場合、さらに待ち行列を確認し、連続してＲロックを要求するスレッドがあればそれらのスレッド情報を順次ポップしてＲロックを獲得させる。ポップしたスレッド情報を、スレッド処理を開始させるプロセスに与えることにより、ロックを獲得したスレッドの処理が再開される。待ち行列にあった最後のスレッド情報をポップする際は、図６と同様にダミーの要素をプッシュする。
【００９２】
なおＷロックを解除するスレッドは、先頭のスレッド情報ａのみをポップし、後続のスレッド情報は確認しないようにしてもよい。この場合、処理を開始したスレッド情報ａのスレッドが、後続のスレッド、すなわち次に待ち行列の先頭に来たスレッド情報ｂを確認し、Ｒロックであった場合は当該スレッド情報ｂをポップして対応するスレッド処理を開始させる、というように、連鎖的にロック獲得の可否を確認するようにしてもよい。
【００９３】
ロックを要求する際の処理手順は図１５のフローチャートで示したのと同様である。ただしＳ６０の判定は、要求するロックを獲得できるか否かの判定となり、Ｓ６２およびＳ６６で更新する情報はＲＷロックの情報となる。ロックを解除する際の処理手順は図１６のフローチャートで示したのと同様である。ただしＳ７４の判定は、要求するロックを獲得できるか否かの判定となり、Ｓ７２で更新する情報はＲＷロックの情報となる。
【００９４】
このような構成とすることで、ＲＷロックの管理機能とロック獲得待ちスレッドのキューの機能を同時に実現することができる。これらの機能は同じキューに対するアトミック操作で実現できることから、ロックを獲得することのできないスレッドを即座に待機状態としてプロセッサを開放することができる。またロックを獲得できる状態となったら待機状態となっていたスレッドの処理を即座に再開させることができる。これらの処理はノンブロッキングで行われることから、キューへのアクセス、ロックの獲得及び解除、スレッドの待機および処理の再開といった各ステップにおいてスレッドの待ち時間を減らすことができる。
【００９５】
以上、本発明を実施の形態をもとに説明した。上記実施の形態は例示であり、それらの各構成要素や各処理プロセスの組合せにいろいろな変形例が可能なこと、またそうした変形例も本発明の範囲にあることは当業者に理解されるところである。
【符号の説明】
【００９６】
１０  情報処理装置、  １２ａ  処理ユニット、  １４  共有メモリ、  １６ａ  プロセッサ、  １８ａ  ローカルメモリ、  ２２  キュー、  ２８  リンクリスト。
【図１】
0005553685.tif 000002
【図２】
0005553685.tif 000003
【図３】
0005553685.tif 000004
【図４】
0005553685.tif 000005
【図５】
0005553685.tif 000006
【図６】
0005553685.tif 000007
【図７】
0005553685.tif 000008
【図８】
0005553685.tif 000009
【図９】
0005553685.tif 000010
【図１０】
0005553685.tif 000011
【図１１】
0005553685.tif 000012
【図１２】
0005553685.tif 000013
【図１３】
0005553685.tif 000014
【図１４】
0005553685.tif 000015
【図１５】
0005553685.tif 000016
【図１６】
0005553685.tif 000017
【図１７】
0005553685.tif 000018
【図１８】
0005553685.tif 000019