(57)【要約】      （修正有）【課題】複数のスレッド間でのデータ競合を解決する。【解決手段】情報処理装置１００は、マルチスレッドプログラムの複数のスレッドに、データ競合を発生させずに同一のライブラリを利用させる。情報処理装置１００は、ライブラリロード部１０１及び割当処理部１０２とを含む。ライブラリロード部１０１は、ライブラリより複数のインスタンスを生成してメモリ空間にロードする処理を行う。割当処理部１０２は、ライブラリロード部１０１が生成したインスタンスを、複数のスレッドに割当てる処理を行う。【選択図】図２
2013029979.tif 000002
【特許請求の範囲】
【請求項１】
マルチスレッドプログラムの複数のスレッドに、データ競合を発生させずに同一のライブラリを利用させる情報処理装置であって、
前記ライブラリより複数のインスタンスを生成し、前記複数のインスタンスをメモリ空間にロードするライブラリロード部と、
前記ライブラリロード部が生成した前記複数のインスタンスを、前記複数のスレッドに割当てる割当処理部とを含む
情報処理装置。
【請求項２】
前記ライブラリロード部は、同一の前記ライブラリから、毎度異なるインスタンスを生成する処理を行うことにより、前記新たなインスタンスを生成する
請求項１記載の情報処理装置。
【請求項３】
前記ライブラリロード部は、前記ライブラリと同一内容の複製ライブラリであって、毎度異なる前記複製ライブラリからインスタンスを生成する処理を行うことにより、前記新たなインスタンスを生成する
請求項１記載の情報処理装置。
【請求項４】
前記割当処理部は、前記スレッドの識別子と、前記インスタンスに含まれるシンボル又は変数のうち少なくともいずれか一方のアドレスとを対応付けて保持することにより、前記割当てを行う
請求項１乃至３いずれか１項記載の情報処理装置。
【請求項５】
前記割当処理部は、前記アドレスを格納した構造体であって、前記スレッドそれぞれに対して生成されるものであり、
前記スレッドは、前記構造体を参照することにより前記アドレスを取得する
請求項４記載の情報処理装置。
【請求項６】
前記割当処理部は、アドレス表及びラッパー関数を含み、
前記アドレス表は、前記スレッドの識別子と前記アドレスとを対応付けて記録しており、
前記ラッパー関数は、指定された前記スレッドの識別子に対応する前記アドレスを取得するものであり、
前記スレッドは、前記ラッパー関数を実行することにより前記アドレスを取得する
請求項４記載の情報処理装置。
【請求項７】
マルチスレッドプログラムの複数のスレッドに、データ競合を発生させずに同一のライブラリを利用させる情報処理方法であって、
前記ライブラリより複数のインスタンスを生成し、前記複数のインスタンスをメモリ空間にロードするロード処理と、
前記複数のインスタンスを、前記複数のスレッドに割当てる割当処理とを含む
情報処理方法。
【請求項８】
前記ロード処理は、同一の前記ライブラリから、毎度異なるインスタンスを生成する処理を行うことにより、前記新たなインスタンスを生成するものである
請求項７記載の情報処理方法。
【請求項９】
前記ロード処理は、前記ライブラリと同一内容の複製ライブラリであって、毎度異なる前記複製ライブラリからインスタンスを生成する処理を行うことにより、前記新たなインスタンスを生成するものである
請求項７記載の情報処理方法。
【請求項１０】
前記割当処理は、前記スレッドの識別子と、前記インスタンスに含まれるシンボル又は変数のうち少なくともいずれか一方のアドレスとを対応付けて保持することにより、前記割当てを行うものである
請求項７乃至９いずれか１項記載の情報処理方法。
【発明の詳細な説明】
【技術分野】
【０００１】
本発明は、マルチスレッドプログラムの実行方法に関し、特に複数のスレッド間でのデータ競合を解決する方法に関する。
【背景技術】
【０００２】
一般に、複数のスレッドを持つマルチスレッドプログラムを作成する際は、スレッド間でのデータ競合を考慮する必要がある。なぜならば、プログラムの実行中にスレッド間でデータ競合が起こると、意図しないデータの不整合が生じ、プログラムが本来の動作と異なる動作をして障害を引き起こす可能性があるからである。
【０００３】
図２１に、マルチスレッドプログラムでのデータ競合の例を示す。図２１は、２つの関数ｆｕｎｃ０とｆｕｎｃ１が、一時的な記憶領域としてグローバル変数のｘを利用している状況を示している。
【０００４】
図２１（ａ）は、この２つの関数を１つのスレッドが実行する場合を示している。この場合、２つの関数は順番に実行される。そのため、各関数がグローバル変数ｘに書込む（ｗｒｉｔｅ）データと、読出す（ｒｅａｄ）データとは整合する。すなわち、ｆｕｎｃ０がグローバル変数ｘに３というデータを書込んだならば、同じｆｕｎｃ０がｘを読出して得られる値は３である。その後、ｆｕｎｃ１がグローバル変数ｘに６というデータを書込んだならば、同じｆｕｎｃ１がｘを読出して得られる値は６となる。
【０００５】
一方、図２１（ｂ）は、この２つの関数を２つのスレッドで実行する場合を示している。この場合、２つの関数は同時に実行される可能性がある。そのため、各関数がグローバル変数ｘに書込む（ｗｒｉｔｅ）データと、読出す（ｒｅａｄ）データとに不整合が生じることがある。以下、この現象をデータ競合という。データ競合は、例えば、スレッド０が実行した関数ｆｕｎｃ０によってグローバル変数ｘに書込まれた３というデータが、スレッド１が実行した関数ｆｕｎｃ１によって６というデータに上書きされるときに起こり得る。このとき、ｆｕｎｃ０がｘを読出して得られる値は６であり、ｆｕｎｃ０がｘに書込んだはずの３という値とは異なるものとなってしまう。こうしたデータ競合が起こると、これらの関数やスレッドが実行する以後の処理は不正確なものとなる。
【０００６】
このようなデータ競合の１つの解決策として、変数を複数用意し、各スレッドからは異なる変数を利用するように、プログラムのソースコードを修正する手法がある。このような手法をプライベート化という。例えば、図２１の例では、関数ｆｕｎｃ０とｆｕｎｃ１が単一のグローバル変数ｘにアクセスしていた。しかしながら、プログラムを解析することにより、ｆｕｎｃ０とｆｕｎｃ１がそれぞれ異なるグローバル変数にアクセスするようにプログラムを修正しても問題がないと判明したとする。この場合には、ｆｕｎｃ０はグローバル変数ｘ０を利用し、ｆｕｎｃ１はグローバル変数ｘ１を利用するよう、プログラムを修正することで、データ競合を解決することができる。
【０００７】
図２２は、この手法によりデータ競合を解決した例を示している。図２２の例においては、関数ｆｕｎｃ０及びｆｕｎｃ１はそれぞれ別のグローバル変数ｘ０及びｘ１にアクセスするため、上述のようなデータ競合の問題は発生しない。
【０００８】
特許文献１は、複数のスレッド間で共有される変数をプライベート化した実行コードを生成するコンパイラを開示している。なお、ここでいう変数とは、典型的にはグローバル変数である。また、この実行コードは、プログラム実行時、グローバル変数に対する最初のアクセスがなされた際に、プライベート化を行うものである。
【先行技術文献】
【特許文献】
【０００９】
【特許文献１】特開２００１−１４２７１９号公報
【発明の概要】
【発明が解決しようとする課題】
【００１０】
データ競合の他の解決策としては、図２３に示すように、関数ｆｕｎｃ０とｆｕｎｃ１とが同時に実行されないよう、複数のスレッドが協調して動作するようにプログラムのソースコード修正する手法も考えられる。
【００１１】
図２２及び図２３に示したようなデータ競合の解決手法は、いずれもプログラムのソースコードが必要であるという点において共通する。
【００１２】
一方で、このようなデータ競合が、プログラムが利用するライブラリで起こることが問題となる場合がある。ライブラリとは、再利用可能なコード群であって、プログラムから呼び出されることにより実行可能となるコード群をいう。ここでいうコードとは、ソースコード、オブジェクトコード又は他の任意の形式のものであってよい。一般に、ライブラリはライブラリファイルの形で記憶装置上に配置されているが、実行時にはライブラリファイルのインスタンスがメモリ空間上に配置される。プログラムは、メモリ空間におけるライブラリのインスタンスのアドレスを指定することにより、ライブラリの関数及び変数等にアクセスすることができる。
【００１３】
図２４に、マルチスレッドプログラム内の複数のスレッドが、２つのライブラリ関数を同時に呼び出した場合に問題が起こる例を示す。２つのライブラリ関数ｆｕｎｃ０及びｆｕｎｃ１は、いずれも同一のグローバル変数にアクセスするものである。このｆｕｎｃ０とｆｕｎｃ１とが別々のスレッドで実行されると、データ競合が発生する。
【００１４】
複数のスレッドから呼び出された場合にも正しく動作するように作られたライブラリは、スレッドセーフなライブラリと呼ばれ、このようなライブラリのみを利用する場合は、上述のようなライブラリ内でのデータ競合は起こらない。しかしながら、必ずしもプログラムが利用するライブラリすべてがスレッドセーフであるとは限らない。そのため、マルチスレッドプログラムの開発者は、プログラムが利用するライブラリがスレッドセーフであるかを常に把握し、スレッドセーフでない場合にはデータ競合に対応させるための修正を行う必要があった。
【００１５】
ライブラリがスレッドセーフでない場合の対応策として、図２３において示したように、ライブラリ関数を同時に呼び出さないよう、複数のスレッドが時間的に協調して動作するようにプログラムを変更する方法がある。但し、この方法には、ライブラリ関数を同時に呼び出すことができなくなること、ライブラリ関数を呼び出すたびに、他のスレッドが同じ関数を実行していないかをチェックするためのオーバヘッドがかかるため、性能が低下する可能性があることといった欠点がある。
【００１６】
また、ライブラリがスレッドセーフでない場合の他の対応策として、ライブラリのデータ競合自体を解決する方法がある。すなわち、図２２において示したようなソースコードの修正をライブラリに対して行うことによって、ライブラリをスレッドセーフに変更することができる。しかしながら、この方法には、ライブラリのソースコードが必ずしも利用できるとは限らないという欠点がある。ライブラリのソースコードが利用出来ない場合は、特許文献１にみられるような、コンパイラによるプライベート化を行うこともできない。
【００１７】
本発明は、このような問題点を解決するためになされたものであり、複数のスレッド間でのデータ競合を解決することができる情報処理装置及び情報処理方法を提供することを目的とする。
【課題を解決するための手段】
【００１８】
本発明に係る情報処理装置は、マルチスレッドプログラムの複数のスレッドに、データ競合を発生させずに同一のライブラリを利用させる情報処理装置であって、前記ライブラリより複数のインスタンスを生成し、前記複数のインスタンスをメモリ空間にロードするライブラリロード部と、前記ライブラリロード部が生成した前記複数のインスタンスを、前記複数のスレッドに割当てる割当処理部とを含むものである。
【００１９】
また、本発明にかかる情報処理方法は、前記ライブラリより複数のインスタンスを生成し、前記複数のインスタンスをメモリ空間にロードするロード処理と、前記複数のインスタンスを、前記複数のスレッドに割当てる割当処理とを含むものである。
【発明の効果】
【００２０】
本発明により、複数のスレッド間でのデータ競合を解決することができる情報処理装置及び情報処理方法を提供することができる。
【図面の簡単な説明】
【００２１】
【図１】実施の形態１にかかる情報処理装置１００の構成を示す図である。
【図２】実施の形態１にかかる情報処理装置１００の構成を示す図である。
【図３】実施の形態１にかかる情報処理装置１００の構成（ライブラリ）を示す図である。
【図４】実施の形態１にかかる情報処理装置１００の構成（ロード制御部）を示す図である。
【図５】実施の形態１にかかる情報処理装置１００の構成（スレッド生成部）を示す図である。
【図６】実施の形態１にかかる情報処理装置１００の構成（スレッド）を示す図である。
【図７】実施の形態１にかかる情報処理装置１００の構成（メモリマップ）を示す図である。
【図８】実施の形態１にかかる情報処理装置１００の構成（アドレス構造体）を示す図である。
【図９】実施の形態１にかかる情報処理装置１００の処理を示す図である。
【図１０】実施の形態１にかかる情報処理装置１００の処理を示す図である。
【図１１】実施の形態１にかかる情報処理装置１００の処理と、他の処理方法との比較図である。
【図１２】実施の形態２にかかる情報処理装置１００の構成を示す図である。
【図１３】実施の形態２にかかる情報処理装置１００の構成（スレッド生成部）を示す図である。
【図１４】実施の形態３にかかる情報処理装置１００の構成を示す図である。
【図１５】実施の形態３にかかる情報処理装置１００の構成（アドレス表）を示す図である。
【図１６】実施の形態３にかかる情報処理装置１００の構成（ロード制御部）を示す図である。
【図１７】実施の形態３にかかる情報処理装置１００の構成（ラッパー関数）を示す図である。
【図１８】実施の形態３にかかる情報処理装置１００の構成（スレッド生成部）を示す図である。
【図１９】実施の形態３にかかる情報処理装置１００の構成（スレッド）を示す図である。
【図２０】その他の実施の形態にかかる情報処理装置２００の構成を示す図である。
【図２１】背景技術にかかる処理を示す図である。
【図２２】背景技術にかかる処理を示す図である。
【図２３】背景技術にかかる処理を示す図である。
【図２４】背景技術にかかる処理を示す図である。
【発明を実施するための形態】
【００２２】
以下、本発明を適用した具体的な実施の形態について、図面を参照しながら詳細に説明する。
【００２３】
＜実施の形態１＞
本実施の形態は、本発明を、ライブラリがプログラムにダイナミックリンクされる場面に適用したものある。
【００２４】
ここで、ダイナミックリンクとは、プログラムの実行時に、プログラムに必要なライブラリが、より具体的にはライブラリファイルから生成されたインスタンスが、プログラムのメモリ空間内にロードされ、かつシンボルのアドレス解決が行われる方式である。シンボルのアドレス解決とは、ライブラリ中のシンボル（関数名など）と、プログラムのメモリ空間上のアドレスの対応関係を決定することをいう。このように、アドレス解決を行うことによってはじめて、プログラムはライブラリの関数等を利用することが可能となる。ダイナミックリンクにおいては、ライブラリ中のシンボルのアドレスは、ライブラリがロードされるまで確定されず、アドレスの解決はプログラムの実行時に行われる。
【００２５】
はじめに、図１を用いて、本発明の実施の形態１にかかる情報処理装置１００の基本的な構成について説明する。
【００２６】
情報処理装置１００は、ライブラリロード部１０１と割当処理部１０２とを有する。
【００２７】
ライブラリロード部１０１は、ライブラリファイルから複数のインスタンスを生成し、それらのインスタンスをメモリ空間にロードする処理を行う処理部である。
【００２８】
割当処理部１０２は、ライブラリロード部１０１が生成した複数のインスタンスを、それぞれ複数のスレッドに割当てる処理を行う処理部である。
【００２９】
上記１０１乃至１０２はいずれも、図示しない記憶手段に格納された各種コンピュータプログラムに基づいて各種制御を実行する機能を有しており、具体的には中央演算処理装置（ＣＰＵ）、読出専用メモリ（ＲＯＭ）、ランダムアクセスメモリ（ＲＡＭ）、入出力ポート（Ｉ／Ｏ）等により実現されるものである。
【００３０】
図２を用いて、情報処理１００のより具体的な実装例について説明する。
【００３１】
ライブラリロード部１０１としては、例えばＵＮＩＸ（登録商標）などで利用可能なモジュールであって、動的リンクを行うローダへのインタフェースであるｌｉｂｄｌを用いることができる。ｌｉｂｄｌは、ライブラリの動的ロードを行うための、いくつかの関数を提供しているライブラリである。ｌｉｂｄｌを利用することにより、簡易にライブラリの動的ロードが行えるという利点がある。ｌｉｂｄｌはＵＮＩＸ（登録商標）システムでは広く利用されており、当業者には良く知られている。通常ｌｉｂｄｌはｄｌｏｐｅｎと呼ばれる関数を提供する。ｄｌｏｐｅｎは、指定されたライブラリファイルをプロセスのメモリ空間にロードする処理を行う。通常、ｄｌｏｐｅｎは、同一のライブラリファイルを指定した２度目以降のロード要求に対しては、ライブラリの再ロードは行わず、最初の実行時にロードしたライブラリをそのまま利用する。一方、本実施の形態では、このｄｌｏｐｅｎに代えて、ｄｌｍｏｐｅｎと呼ばれる関数を用いてライブラリの動的ロードを行う。ｄｌｍｏｐｅｎは、同一のライブラリファイルを複数回ロードし、プログラム中の別の領域にマップする機能を有する。また、ｌｉｂｄｌは、ｄｌｓｙｍと呼ばれる、ロードしたライブラリ内のアドレスを解決するための関数も提供しており、本実施の形態では、アドレス解決のためにこの関数を利用する。
【００３２】
また、ライブラリロード部１０１が用いるライブラリファイルとしては、例えばライブラリのソースコードをコンパイルして得られた実行可能オブジェクトを格納したファイルとすることができる。本実施の形態では、このライブラリファイルは通常記憶装置に格納され、必要に応じライブラリロード部１０１によって読み出される。ライブラリロード部１０１は、このライブラリファイルを用いて、毎度新たなライブラリインスタンスを生成し、ロードする機能を有する。すなわち、ライブラリインスタンスを、プログラムのメモリ空間上の都度異なる領域にマップし、そのライブラリインスタンスのシンボルのアドレス解決を行う。本実施の形態では、このように、同一のライブラリがメモリ空間上に複数ロードされ得ることが特徴である。
【００３３】
図３に、ライブラリファイルの具体例（ｌｉｂｓａｍｐｌｅ．ｓｏ）を示す。ｌｉｂｓａｍｐｌｅ．ｓｏは、関数ｆｕｎｃ０及びｆｕｎｃ１を含む。ｆｕｎｃ０及びｆｕｎｃ１は、まずグローバル変数ｘに値を設定し、それぞれ関数ｆｕｎｃ００又はｆｕｎｃ１１を呼び出す。ｆｕｎｃ００及びｆｕｎｃ１１は、それぞれｘを用いて所定の演算を行う関数であり、ｆｕｎｃ０及びｆｕｎｃ１はその結果を受取って呼出し元に返す。なお、図３ではｆｕｎｃ００及びｆｕｎｃ１１の内容は省略している。
【００３４】
本実施の形態では、ライブラリロード部１０１は、ロード制御部により呼び出されて実行される。図４に、呼出元であるロード制御部の具体例（ｌｉｂｒａｒｙ＿ｌｏａｄ）を示す。ロード制御部は、ｌｉｂｄｌのｄｌｍｏｐｅｎ関数を呼び出して、ライブラリファイルｆｉｌｅｎａｍｅをロードする。次に、ｄｌｓｙｍ関数を呼び出して、ライブラリインスタンスｐ内の関数ｆｕｎｃ０及びｆｕｎｃ１のアドレスを解決し、新たに生成したアドレス構造体ｈに設定して、呼出し元に返す。なお、アドレス構造体ｈについては後述する。本実施の形態におけるロード制御部は、このようにｄｌｍｏｐｅｎを利用している。そのため、ロード制御部は起動される度に新たなライブラリインスタンスｐを生成する。この際、アドレス構造体ｈに格納される関数ｆｕｎｃ０及びｆｕｎｃ１のアドレスも、毎回異なるアドレスとなる。
【００３５】
本実施の形態では、ロード制御部はスレッド生成部が出すロード要求に応じて実行される。スレッド生成部は、マルチスレッドプログラムにおける複数のスレッドを生成する機能とともに、それぞれのスレッドを生成する際にロード制御部に対してロード要求を出す機能を備えている。このとき、スレッド生成部は、ロードを要求したスレッドの識別子をロード制御部に対して通知することとしてもよい。ロード制御部は、スレッド制御部からこのロード要求を受けると、ライブラリロード部１０１を起動し、ライブラリをロードさせる。また、ロード制御部は、ライブラリロード部１０１が解決したアドレスをライブラリロード部１０１から取得し、割当処理部１０２に通知する機能を備えていてもよい。
【００３６】
図５に、スレッド生成部の具体例を示す。本実施の形態におけるスレッド生成部は、２つのスレッドを生成するものとする。よって、スレッド生成部は、ライブラリ（ｌｉｂｓａｍｐｌｅ．ｓｏ）を２回ロードする。そのため、スレッド生成部は、ロード制御部（ｌｉｂｒａｒｙ＿ｌｏａｄ関数）を２度呼出す。上述したように、ロード制御部は、それぞれのスレッド用のライブラリインスタンスを生成し、それぞれライブラリインスタンスの関数ｆｕｎｃ０及びｆｕｎｃ１のアドレスを格納した、アドレス構造体を返す。つぎに、スレッド生成部はｔｈｒｅａｄ＿ｃｒｅａｔｅ関数を２回実行して、スレッド０及び１を生成する。ここで、ｔｈｒｅａｄ＿ｃｒｅａｔｅ関数の引数は、生成したスレッドが実行すべき関数と、その関数に渡すべき引数を示している。本実施の形態では、生成されたスレッドそれぞれに対し、ロード制御部が生成した構造体ｈを引数として引渡している。
【００３７】
図６に、スレッド生成部により生成されたスレッド内における、ライブラリの関数の実行例を示す。ｔｈｒｅａｄ＿ｍａｉｎ０及びｔｈｒｅａｄ＿ｍａｉｎ１は、それぞれスレッド０及び１が実行する関数である。スレッド０及び１は、上記関数内において、それぞれアドレス構造体ｈに格納されている関数ｆｕｎｃ０又はｆｕｎｃ１のアドレスを指定することにより、ｆｕｎｃ０又はｆｕｎｃ１を実行する。ここで、スレッド０及び１が参照するアドレス構造体ｈはそれぞれ別のものである。また、これらのアドレス構造体は、それぞれ異なるライブラリインスタンス内の関数ｆｕｎｃ０及びｆｕｎｃ１のアドレスを格納している。そのため、これらの２つのスレッドは、別々のライブラリインスタンス内の関数ｆｕｎｃ０又はｆｕｎｃ１を呼出すことになる。また、ライブラリ関数ｆｕｎｃ０及びｆｕｎｃ１がアクセスするグローバル変数もそれぞれのライブラリインスタンス内にある。そのため、これらの２つのスレッドは、データ競合を発生させずに、ライブラリを利用することができる。
【００３８】
図６では、２つのスレッドは、それぞれライブラリ関数ｆｕｎｃ０やｆｕｎｃ１を実行している。ここで、ライブラリ関数ｆｕｎｃ０及びｆｕｎｃ１は、いずれももグローバル変数ｘに値を設定する処理を行うものとする。この場合、もしライブラリインスタンスが１つしかなければ、２つのスレッドが同時に実行されると、一方のスレッドがグローバル変数ｘを設定することによって、他方のスレッドが既にグローバル変数ｘ設定したデータが上書きされてしまう可能性がある。すなわちデータ競合が起こる。このとき、グローバル変数ｘを利用して計算を行うｆｕｎｃ００及びｆｕｎｃ１１では、演算の途中で意図せずグローバル変数ｘの値が変わってしまうことになるため、本来得られるべき処理結果とは異なる処理結果が得られることとなり、結果としてプログラムが誤動作する可能性がある。しかしながら、本実施の形態では、上述のように各スレッドで異なるライブラリインスタンスを利用する。すなわち、ｆｕｎｃ０及びｆｕｎｃ１が利用するグローバル変数ｘは、それぞれ異なる領域に格納された、別の実体を有する変数である。そのため、上述のようなデータ競合は発生しない。したがって、２つスレッドで同時にｆｕｎｃ０やｆｕｎｃ１を実行したとしても、プログラムが誤動作することはない。
【００３９】
このように、本実施の形態では、ライブラリ自体には特別な変更を加えることなく、スレッドセーフではないライブラリをマルチスレッドプログラムで用いることができる。そのため、ライブラリを利用するプログラマの負担を抑えることができる。
【００４０】
図７に、上述のスレッド生成部により生成される２つのスレッドを含むマルチスレッドプログラムのメモリマップを示す。メモリ空間には、２つのライブラリインスタンス０及び１がロードされており、それぞれのライブラリインスタンスは、グローバル変数ｘ、関数ｆｕｎｃ０及びｆｕｎｃ１を備えていることがわかる（ｆｕｎｃ００及びｆｕｎｃ１１は省略する）。
【００４１】
割当処理部１０２は、複数のスレッドそれぞれが、異なるライブラリインスタンスを利用できるように、スレッドがライブラリインスタンスとの対応関係を制御する機能を有する。本実施の形態では、割当処理部１０２は、ロード制御部から、解決済みのアドレスと、このアドレスを利用するスレッドの識別子とを受取り、これらの情報を対応付けて保持することにより、上記制御を行う。より具体的には、割当処理部１０２は、ライブラリインスタンスに対応して生成されるアドレス構造体として実現される。アドレス構造体は、解決済みのアドレス、すなわちライブラリインスタンス内の関数や変数にアクセスするためのアドレスを格納する。なお、割当処理部１０２は、上記アドレス等をロード制御部から受取るのみでなく、他の任意の方法により取得してもよい。
【００４２】
図８に、上述のアドレス構造体の具体例を示す。このアドレス構造体は、ライブラリインスタンス中の関数ｆｕｎｃ０及びｆｕｎｃ１のアドレスを格納することができる。
【００４３】
つぎに、本発明の実施の形態１にかかる情報処理装置１００の処理手順について説明する。
【００４４】
まず、図９に、ライブラリをロードする処理の例を示す。
【００４５】
Ｓ１０１：マルチスレッドプログラムが、スレッド生成部に対してスレッド生成要求を行う。スレッド生成部は、このスレッド生成要求を受取ると、ロード制御部に対してライブラリのロードを要求する。このロード要求は、生成すべきスレッドの数だけ繰返し行われる。好ましくは、スレッド生成部は、ロード要求の際、ロード制御部にスレッド識別子を通知する。
【００４６】
Ｓ１０２：ロード制御部が、ライブラリロード部１０１に対して、ライブラリのロードを要求する。
【００４７】
Ｓ１０３：ライブラリロード部１０１は、記憶手段からライブラリファイルを読出し、新たなライブラリインスタンスを生成し、プログラム（プロセス）のメモリ空間にロードする。
【００４８】
Ｓ１０４：ロード制御部は、ロードされたライブラリに含まれる、外部からアクセス可能なシンボル、すなわち公開されているシンボルのアドレスを、ライブラリロード部１０１に問合せる。ここで、シンボルとは、ライブラリに含まれる関数及び変数等のことである。ライブラリロード部１０１は、上記シンボルのアドレスをロード制御部に返答する。ロード制御部は、割当処理部１０２に対して、特定のスレッド識別子で識別されるスレッドと、上記手順で得られたアドレスとを通知する。割当処理部１０２は、上記スレッドと上記アドレスをと対応付けて保持する。この対応付けは、公開されているすべてのシンボルに対して行われる。対応付けが終了したなら、ロード制御部は、スレッド生成部に対して、ライブラリのロードが完了したことを通知する。
【００４９】
Ｓ１０５：スレッド生成部は、マルチスレッドプログラムにより指示された数のスレッドを生成する。
【００５０】
以上の一連の処理により、スレッドが生成されるたびに、スレッド固有のライブラリインスタンスがプロセスのメモリ空間にロードされる。なお、本実施の形態では、エラー処理（例えば存在しないライブラリのロードを要求した場合等の処理）に関する説明を省略しているが、適宜エラー処理を行うことが好ましい。
【００５１】
つづいて、図１０を用いて、生成されたスレッドがライブラリを呼出す処理について説明する。なお、スレッドがライブラリを呼出すとは、スレッドがライブラリ内の関数を実行すること、及びライブラリ内の変数にアクセスすることをいう。
【００５２】
Ｓ１０６：スレッドは、割当処理部１０２を用いて、スレッド自身のスレッド識別子と実行したいシンボルの識別子とに基づき、スレッド自身に対応付けられたライブラリインスタンス内のシンボルのアドレスを決定する。
【００５３】
Ｓ１０７：スレッドは、決定した上記アドレスを用いてライブラリを呼出す。すなわち、ライブラリ呼出しが関数呼出しの場合は、決定したアドレスにある関数を実行する。また、ライブラリ呼出しが変数への読み書きの場合は、決定したアドレスへの読書きを行う。
【００５４】
このように、スレッド識別子を用いてライブラリ呼出しに必要なアドレスを決定することで、スレッド毎に異なるライブラリインスタンスを呼出すことができる。
【００５５】
図１１に、本実施の形態によってライブラリ関数を実行した場合と、本実施の形態によらずスレッドを同期させた場合、すなわち複数のスレッドで同時にライブラリ関数が呼出されないように制御した場合との動作を比較して示す。スレッドの同期を用いる場合には、一方のスレッドがライブラリ関数の実行を終了するまで、他方のスレッドはライブラリ関数の実行を待機することになる。一方、本実施の形態では、２つのスレッドが同時にライブラリ関数を実行する。よって、本実施の形態の方が、ライブラリ関数の実行を早く終了させることができる。このように、本発明によれば、スレッドセーフでないライブラリを用いる際の性能低下を抑えることができる。
【００５６】
本実施の形態では、スレッド生成部は、ライブラリのロードが完了した後にスレッドを生成したが、スレッドの生成を先に行っても良い。この場合、生成されたスレッドが、ライブラリのロードが終わるより前にライブラリを呼出すことがないよう、適切な処理を行う必要がある。
【００５７】
また、本実施の形態では、ロード制御部は、ライブラリがロードされた際に、ロードされたライブラリのシンボルのアドレスを割当処理部１０２に通知したが、この通知はスレッドがライブラリを呼出した際に行ってもよい。この場合、割当処理部１０２が、ライブラリロード部１０１を呼出し、ライブラリのインスタンス内のシンボルのアドレスを解決するという動作を行う必要がある。これにより、ライブラリのロード時にシンボルのアドレス解決に掛かる時間を省けるため、ライブラリのロードを短時間で行うことができるという効果がある。
【００５８】
さらに、本実施の形態では、ライブラリが公開しているすべてのシンボルについてアドレス解決を行ったが、スレッドが利用するライブラリのシンボルが一部に限られている場合は、そのシンボルのみアドレスの解決を行うこととしてもよい。この場合、あらかじめスレッドが呼び出す可能性があるシンボルを所定の記憶領域に書き出すなどしてライブラリロード部１０１やロード制御部に把握させる必要が生じる。一方、これにより、アドレス解決に必要な処理を少なくすることができるという効果がある。
【００５９】
また、本実施の形態では、ライブラリの全体をプロセスのメモリ空間の複数の領域にマップしたが、ライブラリの一部だけを複数の領域にマップするようにしてもよい。例えば、データ競合が発生する関数だけ複数の領域にマップして別々のスレッドから利用可能とし、データ競合が発生しない関数は、すでにマップされた領域内の関数を利用することができる。この場合、あらかじめデータ競合が発生する可能性のあるシンボルを所定の記憶領域に書き出すなどしてライブラリロード部１０１やロード制御部に把握させる必要が生じる。一方、これにより、メモリ空間上でライブラリインスタンスが占める領域のサイズを少なく抑えることができる。
【００６０】
さらに、本実施の形態では、スレッド生成時にライブラリをロードする例を示したが、ライブラリのロードのタイミングは、技術的に可能とされる他の適宜のタイミングであってよい。
【００６１】
また、本実施の形態では、説明を簡潔にするために、プログラムが１つのライブラリを利用する場合を例として説明したが、本発明はこれにとどまらず、複数のライブラリを用いる場合にも利用し得る。複数のライブラリを利用する場合には、プログラムが利用するすべてのライブラリに対して本実施の形態を適用しても良く、また特定のライブラリ（スレッドセーフではないライブラリなど）に対して本実施の形態を適用しても良い。
【００６２】
本実施の形態においては、ロード制御部がライブラリロード部１０１を用いてスレッド毎にライブラリインスタンスを生成し、割当処理部１０２がスレッドとライブらいインスタンスとの対応関係を管理することにより、スレッドセーフではないライブラリを用いる場合であっても、ライブラリ内でのデータ競合を発生させることなく、マルチスレッドプログラムを正しく動作させることができる。
【００６３】
また、本実施の形態においては、ライブラリのソースコードを修正することなく、ライブラリ内でのデータ競合を解決できるため、プログラマの負担を軽減することができる。
【００６４】
さらに、本実施の形態においては、マルチスレッドプログラムでスレッドセーフでないライブラリを用いる際に同期処理を用いないため、同期処理に必要なロックによるオーバヘッドを軽減でき、プログラムの性能を向上させることができる。
【００６５】
＜実施の形態２＞
つぎに、図１２を用いて、本発明の実施の形態２にかかる情報処理装置１００の構成について説明する。
【００６６】
本実施の形態の情報処理装置１００も、上述の実施の形態１と同様に、ライブラリロード部１０１と割当処理部１０２とを有する。
【００６７】
本実施の形態のライブラリロード部１０１は、同一のライブラリファイルを複数回ロードする機能を備えないことを特徴とする。すなわち、ライブラリロード部１０１は、１つのライブラリファイルに格納されたライブラリを１回のみロードするため、メモリ空間上の複数の領域にロードすることはない。かかる機能は、具体的には、上述のｄｌｏｐｅｎ関数を用いることにより実現することができる。また、ライブラリロード部１０１は、実施の形態１と同様に、ロードされたライブラリのシンボルのアドレスを解決行う機能を有する。
【００６８】
また、本実施の形態は、ライブラリファイルが複数存在することを特徴とする。これらのライブラリファイルは、いずれも同じライブラリを格納したライブラリファイルである。これらのライブラリファイルは、例えばライブラリファイルを複製することによって作成することができる。また、ライブラリファイルは、プログラムが利用するスレッドの数だけ複製されることが望ましい。この複製は、スレッド生成部が行ってもよく、ライブラリロード部１０１が行ってもよく、あるいは他の任意の処理部が適宜行うこととしてもよい。
【００６９】
図１３に、本実施の形態におけるスレッド生成部の具体例を示す。本実施例のライブラリロード部１０１は、１つのライブラリファイルから複数のライブラリインスタンスを生成することができない。そのため、スレッド生成部は、ロード制御部（ｌｉｂｒａｒｙ＿ｌｏａｄ関数）に、異なるファイル名を指定してライブラリのロード要求を行っている。なお、スレッド生成部はロード制御部に対して同一のライブラリファイル名を指定し、ロード制御部が都度異なるファイル名をライブラリロード部１０１に対して指定することとしてもよい。ここで、異なるライブラリファイルの指定方法としては、例えば、ライブラリファイルの使用履歴を利用して未使用のライブラリファイルを選択する方法、使用後のライブラリファイルを破棄して再使用不能とする方法、スレッド識別子に対応したライブラリファイルをあらかじめ生成しておき、ロード要求を行ったスレッドのスレッド識別子に対応するライブラリファイルを使用する方法等が考え得るが、他の任意の方法を用いることとしてもよい。
【００７０】
つづいて、本発明の実施の形態２にかかる情報処理装置１００の処理手順について説明する。
【００７１】
図９を用いて、ライブラリをロードする処理の例を示す。本実施の形態の特徴的な処理は、ロード処理（Ｓ１０３）である。
【００７２】
Ｓ１０１：マルチスレッドプログラムが、スレッド生成部に対してスレッド生成要求を行う。スレッド生成部は、このスレッド生成要求を受取ると、ロード制御部に対してライブラリのロードを要求する。このロード要求は、生成すべきスレッドの数だけ繰返し行われる。好ましくは、スレッド生成部は、ロード要求の際、ロード制御部にスレッド識別子を通知する。
【００７３】
Ｓ１０２：ロード制御部が、ライブラリロード部１０１に対して、ライブラリのロードを要求する。ここで、ロード制御部は、毎回異なるライブラリファイルを指定して、ライブラリロード部１０１にライブラリインスタンスの生成を指示する。
【００７４】
Ｓ１０３：ライブラリロード部１０１は、記憶手段からライブラリファイルを読出し、ライブラリインスタンスを生成し、プログラム（プロセス）のメモリ空間にロードする。ライブラリロード部１０１は、毎回異なるライブラリファイルを用いてライブラリインスタンスを生成する。
【００７５】
Ｓ１０４：ロード制御部は、ロードされたライブラリに含まれる、外部からアクセス可能なシンボル、すなわち公開されているシンボルのアドレスを、ライブラリロード部１０１に問合せる。ここで、シンボルとは、ライブラリに含まれる関数及び変数等のことである。ライブラリロード部１０１は、上記シンボルのアドレスをロード制御部に返答する。ロード制御部は、割当処理部１０２に対して、特定のスレッド識別子で識別されるスレッドと、上記手順で得られたアドレスとを通知する。割当処理部１０２は、上記スレッドと上記アドレスをと対応付けて保持する。この対応付けは、公開されているすべてのシンボルに対して行われる。対応付けが終了したなら、ロード制御部は、スレッド生成部に対して、ライブラリのロードが完了したことを通知する。
【００７６】
Ｓ１０５：スレッド生成部は、マルチスレッドプログラムにより指示された数のスレッドを生成する。
【００７７】
スレッドがライブラリを呼び出す際の処理（Ｓ１０６乃至Ｓ１０７）は、第１の実施の形態と全く同様に行うことができるため、説明を省略する。
【００７８】
本実施の形態においては、ライブラリロード部１０１が、複製されたライブラリファイルを利用して、同一のライブラリをメモリ空間上の複数の領域にロードするため、同一のライブラリファイルを複数ロードする機能を備えていない場合であっても、データ競合を起こすことなく、スレッドセーフでないライブラリを利用することができる。
【００７９】
＜実施の形態３＞
つぎに、図１４を用いて、本発明の実施の形態３にかかる情報処理装置１００の構成について説明する。
【００８０】
本実施の形態の情報処理装置１００も、上述の実施の形態１と同様に、ライブラリロード部１０１と割当処理部１０２とを有する。なお、ライブラリロード部１０１及びライブラリファイルは、実施の形態２と同様の構成であってもよい。
【００８１】
本実施の形態の割当処理部１０２は、アドレス構造体の代わりに、アドレス表とラッパー関数とを利用することを特徴とする。
【００８２】
図１５に、本実施の形態におけるアドレス表の例を示す。本実施の形態でも、実施の形態１と同様に、ライブラリは関数ｆｕｎｃ０及びｆｕｎｃ１を外部に公開している。また、プログラムはスレッド０及び１を利用する。図１５のアドレス表は、これらのスレッドそれぞれに対して、関数ｆｕｎｃ０及びｆｕｎｃ１のアドレスを格納している。
【００８３】
図１６に、本実施の形態におけるロード制御部の例を示す。本実施の形態におけるロード制御部は、実施の形態１と同様に、ｄｌｍｏｐｅｎを利用してライブラリをロードした後に、ｄｌｓｙｍを用いてライブラリ関数のアドレスを解決する。ここで、ロード制御部が、解決したアドレスをアドレス表に記録することが本実施例の特徴である。これにより、各スレッド用のライブラリインスタンス内の関数のアドレスがアドレス表に記録される。
【００８４】
図１７に、本実施の形態におけるラッパー関数の例を示す。ラッパー関数とは、ライブラリ関数と同様のインターフェース（関数名と引数）を持った関数であって、スレッドからライブラリ関数の代わりに呼び出される関数である。ラッパー関数は、呼び出されるとまず呼び出したスレッドの識別子を取得し、次にアドレス表を検索して、スレッド識別子に対応するアドレスの関数を実行する。これにより、スレッドは、ラッパー関数を呼び出すことによって、スレッド毎に異なるライブラリインスタンス内の関数を呼び出すことができる。
【００８５】
図１８に、本実施の形態におけるスレッド生成部の例を示す。本実施の形態におけるスレッド生成部は、１つのスレッドを生成するｃｒｅａｔｅ＿ｔｈｒｅａｄ関数と、それを２回呼び出すことによって２つのスレッドを生成するｃｒｅａｔｅ＿ｔｈｒｅａｄｓ関数とを含む。ｃｒｅａｔｅ＿ｔｈｒｅａｄ関数は、ロード制御部を呼び出してライブラリをロードした後に、ｔｈｒｅａｄ＿ｃｒｅａｔｅ関数を呼び出してスレッドを生成する。なお、ｔｈｒｅａｄ＿ｃｒｅａｔｅ関数とは、通常スレッドライブラリによって提供される関数である。これにより、スレッド生成部は、スレッド生成のたびに、そのスレッド専用のライブラリをロードすることができる。
【００８６】
図１９に、本実施例のスレッドが実行する関数の例を示す。２つのスレッドは、それぞれライブラリ関数ｆｕｎｃ０又はｆｕｎｃ１を呼び出す。ただし、本実施例では、実施の形態１のように直接ライブラリ関数を呼び出すのではなく、ラッパー関数を経由してライブラリ関数を呼び出す。これにより、各スレッドはそれぞれ異なるライブラリインスタンス内のライブラリ関数を呼び出すこととなり、データ競合の発生を防止することができる。  
【００８７】
本実施の形態においては、割当処理部１０２として、ライブラリ関数のインターフェースは同一のラッパー関数を用いるため、スレッドは、直接ライブラリ関数を呼び出す場合とほぼ同様の手順でライブラリ関数を利用することができる。これにより、例えばシングルスレッド用のプログラムをマルチスレッド用に変更する場合などに、プログラムの修正量を少なくすることができる。
【００８８】
＜その他の実施の形態＞
なお、本発明は上述した実施の形態のみに限定されるものではなく、本発明の要旨を逸脱しない範囲において種々の変更が可能であることは勿論である。
【００８９】
例えば、上述の実施の形態では、主にライブラリを動的にリンクする場合を例として本発明を説明したが、本発明はライブラリを静的にリンク（スタティックリンク）する場合にも適用できる。スタティックリンクとは、プログラムのコンパイル時にライブラリをリンクする方式である。一例として、図２０に本発明をスタティックリンクに適用した場合の情報処理装置２００の構成例を示す。
【００９０】
スタティックリンク方式においては、コンパイラから呼び出される静的リンカがリンクを行う。情報処理装置２００の形態の静的リンカは、一般的な静的リンカの機能に加えて、一つのライブラリファイルを複数回プログラムにリンクする、すなわち複数のライブラリインスタンスをプログラムに静的リンクするという機能を有する。このとき、ライブラリインスタンスの数は、プログラムが利用するスレッド数と等しいことが望ましい。また、静的リンカは、スレッド毎に異なるライブラリインスタンスを呼び出すように、アドレス制御部に対して、各ライブラリインスタンス内のシンボルのアドレスを通知する機能を有することが望ましい。
【００９１】
また、上述の実施の形態では、ハードウェアの構成として説明したが、これに限定されるものではなく、任意の処理を、ＣＰＵ（Ｃｅｎｔｒａｌ  Ｐｒｏｃｅｓｓｉｎｇ  Ｕｎｉｔ）にコンピュータプログラムを実行させることにより実現することも可能である。この場合、コンピュータプログラムは、様々なタイプの非一時的なコンピュータ可読媒体（ｎｏｎ−ｔｒａｎｓｉｔｏｒｙ  ｃｏｍｐｕｔｅｒ  ｒｅａｄａｂｌｅ  ｍｅｄｉｕｍ）を用いて格納され、コンピュータに供給することができる。非一時的なコンピュータ可読媒体は、様々なタイプの実体のある記録媒体（ｔａｎｇｉｂｌｅ  ｓｔｏｒａｇｅ  ｍｅｄｉｕｍ）を含む。非一時的なコンピュータ可読媒体の例は、磁気記録媒体（例えばフレキシブルディスク、磁気テープ、ハードディスクドライブ）、光磁気記録媒体（例えば光磁気ディスク）、ＣＤ−ＲＯＭ（Ｒｅａｄ  Ｏｎｌｙ  Ｍｅｍｏｒｙ）、ＣＤ−Ｒ、ＣＤ−Ｒ／Ｗ、半導体メモリ（例えば、マスクＲＯＭ、ＰＲＯＭ（Ｐｒｏｇｒａｍｍａｂｌｅ  ＲＯＭ）、ＥＰＲＯＭ（Ｅｒａｓａｂｌｅ  ＰＲＯＭ）、フラッシュＲＯＭ、ＲＡＭ（ｒａｎｄｏｍ  ａｃｃｅｓｓ  ｍｅｍｏｒｙ））を含む。また、プログラムは、様々なタイプの一時的なコンピュータ可読媒体（ｔｒａｎｓｉｔｏｒｙ  ｃｏｍｐｕｔｅｒ  ｒｅａｄａｂｌｅ  ｍｅｄｉｕｍ）によってコンピュータに供給されてもよい。一時的なコンピュータ可読媒体の例は、電気信号、光信号、及び電磁波を含む。一時的なコンピュータ可読媒体は、電線及び光ファイバ等の有線通信路、又は無線通信路を介して、プログラムをコンピュータに供給できる。
【００９２】
上記実施の形態の一部又は全部は、以下の付記のようにも記載されうるが、以下には限られない。
【００９３】
（付記１）
マルチスレッドプログラムの複数のスレッドに、データ競合を発生させずに同一のライブラリを利用させる情報処理装置であって、
前記ライブラリより複数のインスタンスを生成し、前記複数のインスタンスをメモリ空間にロードするライブラリロード部と、
前記ライブラリロード部が生成した前記複数のインスタンスを、前記複数のスレッドに割当てる割当処理部とを含む
情報処理装置。
【００９４】
（付記２）
前記ライブラリロード部は、同一の前記ライブラリから、毎度異なるインスタンスを生成する処理を行うことにより、前記新たなインスタンスを生成する
付記１記載の情報処理装置。
【００９５】
（付記３）
前記ライブラリロード部は、前記ライブラリと同一内容の複製ライブラリであって、毎度異なる前記複製ライブラリからインスタンスを生成する処理を行うことにより、前記新たなインスタンスを生成する
付記１記載の情報処理装置。
【００９６】
（付記４）
前記割当処理部は、前記スレッドの識別子と、前記インスタンスに含まれるシンボル又は変数のうち少なくともいずれか一方のアドレスとを対応付けて保持することにより、前記割当てを行う
付記１乃至３いずれか１項記載の情報処理装置。
【００９７】
（付記５）
前記割当処理部は、前記アドレスを格納した構造体であって、前記スレッドそれぞれに対して生成されるものであり、
前記スレッドは、前記構造体を参照することにより前記アドレスを取得する
付記４記載の情報処理装置。
【００９８】
（付記６）
前記割当処理部は、アドレス表及びラッパー関数を含み、
前記アドレス表は、前記スレッドの識別子と前記アドレスとを対応付けて記録しており、
前記ラッパー関数は、指定された前記スレッドの識別子に対応する前記アドレスを取得するものであり、
前記スレッドは、前記ラッパー関数を実行することにより前記アドレスを取得する
付記４記載の情報処理装置。
【００９９】
（付記７）
マルチスレッドプログラムの複数のスレッドに、データ競合を発生させずに同一のライブラリを利用させる情報処理方法であって、
前記ライブラリより複数のインスタンスを生成し、前記複数のインスタンスをメモリ空間にロードするロード処理と、
前記複数のインスタンスを、前記複数のスレッドに割当てる割当処理とを含む
情報処理方法。
【０１００】
（付記８）
前記ロード処理は、同一の前記ライブラリから、毎度異なるインスタンスを生成する処理を行うことにより、前記新たなインスタンスを生成するものである
付記７記載の情報処理方法。
【０１０１】
（付記９）
前記ロード処理は、前記ライブラリと同一内容の複製ライブラリであって、毎度異なる前記複製ライブラリからインスタンスを生成する処理を行うことにより、前記新たなインスタンスを生成するものである
付記７記載の情報処理方法。
【０１０２】
（付記１０）
前記割当処理は、前記スレッドの識別子と、前記インスタンスに含まれるシンボル又は変数のうち少なくともいずれか一方のアドレスとを対応付けて保持することにより、前記割当てを行うものである
付記７乃至９いずれか１項記載の情報処理方法。
【０１０３】
（付記１１）
前記割当処理は、前記スレッドそれぞれに対して生成される構造体に前記アドレスを格納することにより行うものであり、
前記スレッドは、前記構造体を参照することにより前記アドレスを取得する
付記１０記載の情報処理方法。
【０１０４】
（付記１２）
前記割当処理は、
アドレス表に前記スレッドの識別子と前記アドレスとを対応付けて記録することにより行うものであり、
前記スレッドは、前記スレッドの識別子に基づいて前記アドレスを取得するラッパー関数により前記アドレスを取得する
付記１０記載の情報処理方法。
【符号の説明】
【０１０５】
１００  情報処理装置
１０１  ライブラリロード部
１０２  割当処理部
２００  情報処理装置
【図１】
2013029979.tif 000003
【図２】
2013029979.tif 000004
【図３】
2013029979.tif 000005
【図４】
2013029979.tif 000006
【図５】
2013029979.tif 000007
【図６】
2013029979.tif 000008
【図７】
2013029979.tif 000009
【図８】
2013029979.tif 000010
【図９】
2013029979.tif 000011
【図１０】
2013029979.tif 000012
【図１１】
2013029979.tif 000013
【図１２】
2013029979.tif 000014
【図１３】
2013029979.tif 000015
【図１４】
2013029979.tif 000016
【図１５】
2013029979.tif 000017
【図１６】
2013029979.tif 000018
【図１７】
2013029979.tif 000019
【図１８】
2013029979.tif 000020
【図１９】
2013029979.tif 000021
【図２０】
2013029979.tif 000022
【図２１】
2013029979.tif 000023
【図２２】
2013029979.tif 000024
【図２３】
2013029979.tif 000025
【図２４】
2013029979.tif 000026