(57)【要約】【課題】データ競合しない関数群は複数のコアで並行実行可能としつつ、データ競合する関数対は時間分離して実行させる。【解決手段】プログラム変換装置２２Ａは、並行実行可能な関数列２０を入力として、データ競合する関数対は時間分離して実行されるようにそれらの関数間にプロセスバリア３０を挿入し、ロックフリー関数キューＬＦＱ１を出力し、プロセスバリア３０は、データ競合する前後の関数のうち、前の関数の実行が完了するまで、後の関数の実行をプロセスバリア３０の位置で待機させるとともに、データ競合する前後の関数のうち、前の関数の実行が完了したかを監視する。【選択図】図１
2019204387.tif 000002
【特許請求の範囲】
【請求項１】
並行実行可能な複数の関数が順々に登録されたロックフリー関数キューを保持し、
前記ロックフリー関数キューは、データ競合する関数間に挿入されたプロセスバリアを含み、
前記プロセスバリアは、前記データ競合する前後の関数のうち、前の関数の実行が完了するまで、後の関数の実行を前記プロセスバリアの位置で待機させるプログラム実行制御方法。
【請求項２】
前記プロセスバリアは、前記データ競合する前後の関数のうち、前の関数の実行が完了したかを監視し、前の関数の実行が完了すると、後の関数を実行するコアの割り当てを許容する請求項１に記載のプログラム実行制御方法。
【請求項３】
前記プロセスバリアは、
指定の関数の処理完了を確認するチェッカと、
前記プロセスバリアより後の関数の実行を待機させるリミッタとを備え、
前記チェッカは、前記指定の関数の処理完了を確認すると、前記チェッカと対となる前記リミッタを前記ロックフリー関数キューから削除し、
前記コアは、
前記プロセスバリアの処理時に前記関数の取得および実行を中断し、
前記リミッタの削除後に、前記ロックフリー関数キューから前記関数を取得して実行する処理を再開する請求項２に記載のプログラム実行制御方法。
【請求項４】
前記ロックフリー関数キューに登録された関数を実行するＮ（Ｎは２以上の整数）個のコアを備え、
前記データ競合する前後の関数のうち前の関数の実行するコアと、前記前の関数の実行が完了したかを監視するコアとは互いに異なる請求項２に記載のプログラム実行制御方法。
【請求項５】
前記ロックフリー関数キューに登録された各関数は、自身の関数の処理が終了したかどうかを示すフラグを備える請求項２に記載のプログラム実行制御方法。
【請求項６】
前記ロックフリー関数キューに登録された関数を前記プロセスバリアで区分けした各範囲に含まれる関数間では前記データ競合が発生しない請求項２に記載のプログラム実行制御方法。
【請求項７】
前記プロセスバリアで区分けされた区間に含まれる関数の個数が最大になるように前記プロセスバリアの位置を設定する請求項６に記載のプログラム実行制御方法。
【請求項８】
前記データ競合する前後の関数において、前記監視対象となる前の関数とデータ競合する後の関数が複数ある場合、前記後の関数のうちの最前の関数に対してのみ前記プロセスバリアが挿入される請求項２に記載のプログラム実行制御方法。
【請求項９】
並行実行可能な関数間でデータ競合が発生するかどうかを判定し、前記データ競合が発生する関数間にプロセスバリアを挿入する処理をプロセッサに実行させるプログラム変換装置であって、
前記プロセスバリアは、前記データ競合する前後の関数のうち、前の関数の実行が完了するまで、後の関数の実行を前記プロセスバリアの位置で待機させるプログラム変換装置。
【請求項１０】
前記データ競合は、前後の関数の少なくとも一方が共有データまたは共有リソースに更新処理を実行して引き起こされる競合である請求項９に記載のプログラム変換装置。
【請求項１１】
前記プロセスバリアは、前記データ競合する前後の関数のうち、前の関数の実行が完了したかを監視し、前の関数の実行が完了すると、後の関数を実行するコアの割り当てを許容する請求項９に記載のプログラム変換装置。
【請求項１２】
前記ロックフリー関数キューに登録された関数を前記プロセスバリアで区分けした各範囲に含まれる関数間では前記データ競合が発生しない請求項１１に記載のプログラム変換装置。
【請求項１３】
前記プロセスバリアで区分けされた区間に含まれる関数の個数が最大になるように前記プロセスバリアの位置を設定する請求項１２に記載のプログラム変換装置。
【請求項１４】
前記データ競合する前後の関数において、前記監視対象となる前の関数とデータ競合する後の関数が複数ある場合、前記後の関数のうちの最前の関数に対してのみ前記プロセスバリアが挿入される請求項１１に記載のプログラム変換装置。
【請求項１５】
前記プロセスバリアは、
指定の関数の処理完了を確認するチェッカと、
前記プロセスバリアより後の関数の実行を待機させるリミッタとを備え、
前記チェッカは、前記指定の関数の処理完了を確認すると、前記チェッカと対となる前記リミッタを前記ロックフリー関数キューから削除する請求項１１に記載のプログラム変換装置。
【発明の詳細な説明】
【技術分野】
【０００１】
本発明は、マルチコアまたはメニーコアによるプログラムの並列実行を可能とするプログラム実行制御方法およびプログラム変換装置に関する。
【背景技術】
【０００２】
半導体微細化技術が行き詰まり、クロック周期の高速化による性能改善から、多数のコアを１つのＭＰＵ（Ｍｉｃｒｏ  Ｐｒｏｃｅｓｓｉｎｇ  Ｕｎｉｔ）に搭載することによる性能改善が図られるようになり、多様な形態に適したメニーコアＭＰＵがサーバや携帯端末用途などに販売されている。これらの用途では、シングルコアＭＰＵを前提として設計され、データ分離（ｄａｔａ  ｓｅｐａｒａｔｉｏｎ）条件が成立する複数のアプリケーションをＯＳ（Ｏｐｅｒａｔｉｎｇ  Ｓｙｓｔｅｍ）が並行実行制御することにより、メニーコアの性能を引き出す設計を前提としている。この並行実行制御では、ＯＳ内の共有リソースへのリード・ライトアクセスが発生するものの、既存の排他制御機構を用いて強制的に関数を逐次実行させることで時間分離（ｔｅｍｐｏｒａｌ  ｓｅｐａｒａｔｉｏｎ）を図り、データ競合に起因したデータ整合性の不具合の回避に一定の成功を収めている。
【０００３】
しかし、長年、シングルコアを前提として設計、継承および派生開発されてきた制御ソフトウェアでは、グローバル変数に代表される共有リソースに関するアクセス競合が顕著である。そのため、前記のようなデータ分離を前提としたプログラム並行実行をすることができず、ＯＳのサポートもない。データ競合を許容するプログラム並行実行は非決定的（ｎｏｎ−ｄｅｔｅｒｍｉｎｉｓｔｉｃ）な実行後プログラム状態を導くため、デバッグ、テストおよび検証ができなくなる。
【０００４】
また、実際には、割込み処理負荷を分散させるために、複数のコアには設計時点で想定困難な計算負荷が発生する。そのため、関数毎のコア占有時間を用いて明示的に関数割当てをして最適化を図る設計手法でも、時間同期による制御不能無駄時間の上限が不定である限りは、最悪時応答時間の保証をすることも困難である。
【０００５】
従来技術では、タスク間依存関係の制約を考慮して、各コアに静的に割り当てたタスクの実行順序を明示的に制御する多様な方法があるが、２つの共通した課題がある。第１の課題は、コア数Ｎ（Ｎは２以上の整数）に比例してスケールしない共有リソースの使用を前提としている点である。第２の課題は、割込み処理などの外乱負荷のために、設計時点で最適化して決定した静的なタスク割当をして実現される無駄時間の抑制が図られず、最悪応答時間の保証ができない点である。
【０００６】
特許文献１には、逐次実行プログラムを構成する複数のマクロタスク間で制御依存性を分析し、並列実行可能なマクロタスクを各コアに割り当てて、Ｔｉｍｅ−Ｔｒｉｇｇｅｒｅｄ  Ｓｃｈｅｄｕｌｉｎｇ（ＴＴＳ、特許文献１中でスタティックスケジューリング）による時間分離を図る。しかし、これは前記第２の課題を抱えている。
【０００７】
特許文献１に加えて、特許文献２では、制御依存性がある複数のマクロタスクを束ねるプログラム変換機能を追加することを提案している。この技術は、マクロタスクが短時間で終わるため、ＴＴＳ自体のオーバーヘッドが顕在化することへの対策であるが、依然として前記第２の課題を抱えている。
【０００８】
特許文献３は、明示的にプロセス間通信の機構を使い、タスク実行順序と実行開始時点を制御する方法が開示されている。しかし、この方法は、前記第１の課題を抱えている上、コア数やコア構成の変更に対して、設計資産をそのまま移管できず、再設計が必要になる。
【０００９】
特許文献４では、プログラム依存グラフ（ＰＤＧ：Ｐｒｏｇｒａｍ  Ｄｅｐｅｎｄｅｎｃｙ  Ｇｒａｐｈ）に基づき、タスク投入の制御を行う方法が開示されている。このＰＤＧはバリア同期を用いた手法であるが、競合が発生し得る関数を実行する度に全コアの同期待ちが発生するために、実行速度がコア数に対してスケールしない。
【先行技術文献】
【特許文献】
【００１０】
【特許文献１】特開２０１６−１４３３７８号公報
【特許文献２】特開２０１５−００１８０７号公報
【特許文献３】特開２００９−１５１６４５号公報
【特許文献４】特開２００８−０９０５４１号公報
【発明の概要】
【発明が解決しようとする課題】
【００１１】
従来のソフトウェア開発手法における設計、デバッグ、テスト技法、カバレッジ基準および検証手法はすべて、多数の関数を逐次実行し、実行後プログラム状態の再現性および予測性が前提として成立することに依存している。
また、前記再現性および予測性は、制御ソフトウェアに要求される最悪時応答時間を保証するために必要な要件でもある。よって、プログラム並行実行の具体的な実現手段に寄らず、データ分離条件が成立する関数群は複数のコアで並行実行し、データ競合のために時間分離が必要となる関数対は逐次実行される並行実行制御機構が必要である。
特に、コア数の増加に対してスケールしないコア間通信機構に依存せず、設計時に想定困難な割込み負荷に適応して、各コアの計算待ち時間が動的に平準化され、最悪実行時間を保証できるような並列実行制御機構が求められていた。
【００１２】
本発明は、上記事情に鑑みなされたものであり、その目的は、データ競合しない関数群は複数のコアで並行実行可能としつつ、データ競合する関数対は時間分離して実行させることが可能なプログラム実行制御方法およびプログラム変換装置を提供することにある。
【課題を解決するための手段】
【００１３】
上記目的を達成するため、第１の観点に係るプログラム実行制御方法は、並行実行可能な複数の関数が順々に登録されたロックフリー関数キューを保持し、前記ロックフリー関数キューは、データ競合する関数間に挿入されたプロセスバリアを含み、前記プロセスバリアは、前記データ競合する前後の関数のうち、前の関数の実行が完了するまで、後の関数の実行を前記プロセスバリアの位置で待機させる。
【発明の効果】
【００１４】
本発明によれば、データ競合しない関数群は複数のコアで並行実行可能としつつ、データ競合する関数対は時間分離して実行させることができる。
【図面の簡単な説明】
【００１５】
【図１】図１は、第１実施形態に係るプログラム変換方法およびプログラム実行制御方法を示すブロック図である。
【図２】図２は、図１の関数間のデータ競合関係の一例を示す図である。
【図３】図３は、第１実施形態に係るプログラム変換方法を示すフローチャートである。
【図４】図４は、図１のロックフリー関数キューについてのプログラム実行制御方法を示すタイミングチャートである。
【図５】図５は、図１のロックフリー関数キューの実行中に割込みが入った時のプログラム実行制御方法を示すタイミングチャートである。
【図６】図６は、第１実施形態に係るプログラム実行制御方法を示すフローチャートである。
【図７】図７は、第２実施形態に係るプログラム変換方法およびプログラム実行制御方法を示すブロック図である。
【図８】図８は、第２実施形態に係るプログラム変換方法を示すフローチャートである。
【図９】図９は、図１のプログラム変換装置のハードウェア構成例を示すブロック図である。
【発明を実施するための形態】
【００１６】
実施形態について、図面を参照して説明する。なお、以下に説明する実施形態は特許請求の範囲に係る発明を限定するものではなく、また、実施形態の中で説明されている諸要素及びその組み合わせの全てが発明の解決手段に必須であるとは限らない。
【００１７】
図１は、第１実施形態に係るプログラム変換方法およびプログラム実行制御方法を示すブロック図である。
図１において、プログラム変換装置２２Ａはプログラム変換処理を行う。計算機１Ａはプログラム並行実行処理を行う。
【００１８】
まず、プログラム変換装置２２Ａのプログラム変換処理について説明する。
プログラム変換装置２２Ａは、関数列２０を入力として、データ競合する関数対は時間分離して実行されるようにそれらの関数間にプロセスバリア３０を挿入し、ロックフリー関数キューＬＦＱ１を出力する。関数列２０は、並行実行可能な複数の関数２１を備える。図１では、関数列２０が、関数［０］〜関数［４］を備える例を示した。プロセスバリア３０は、データ競合する前後の関数のうち、前の関数の実行が完了するまで、後の関数の実行をプロセスバリア３０の位置で待機させる。この時、プロセスバリア３０は、データ競合する前後の関数のうち、前の関数の実行が完了したかを監視する。プロセスバリア３０は、ロックフリー関数キューＬＦＱ１に登録された関数を実行するＮ個のコアのうち１個のコアに関数の実行の完了を監視させることができる。
【００１９】
ロックフリー関数キューＬＦＱ１の各関数には、自身の関数の処理終了を示す終了フラグ３６が追加される。各関数は、自身の関数の処理が終了すると、自身の終了フラグをｔｒｕｅに設定し、自身の関数の処理が終了してない場合、自身の終了フラグをｆａｌｓｅに設定する。処理が終了してない関数の終了フラグ３６を予めｆａｌｓｅに初期化し、自身の関数の処理が終了すると、自身の終了フラグをｔｒｕｅに設定するようにしてもよい。
【００２０】
プロセスバリア３０は、データ競合する前後の関数のうち、後の関数の直前に配置する。例えば、関数［０］と関数［２］がデータ競合３５Ａを引き起こすものとすると、プロセスバリア３０は、関数［２］の直前に挿入される。この時、プロセスバリア３０には、監視対象として関数［０］が設定される。
【００２１】
また、データ競合する前後の関数において、監視対象となる前の関数とデータ競合する後の関数が複数ある場合、後の関数のうちの最前の関数に対してのみプロセスバリアが挿入される。例えば、関数［０］と関数［２］がデータ競合３５Ａを引き起こし、関数［０］と関数［４］がデータ競合３５Ｂを引き起こすものとすると、プロセスバリア３０は、関数［２］の直前にのみ挿入され、関数［４］の直前には挿入されない。
【００２２】
また、プロセスバリア３０は、ロックフリー関数キューＬＦＱ１に登録された関数［０］〜関数［４］をプロセスバリア３０で区分けされた範囲に含まれる関数間ではデータ競合が発生しないようにする。例えば、プロセスバリア３０の前の関数［０］と関数［１］との間ではデータ競合が発生しない。さらに、プロセスバリア３０の後の関数［２］と関数［３］と関数［４］との間ではデータ競合が発生しない。
【００２３】
また、プロセスバリアで区分けされた区間に含まれる関数の個数が最大になるようにプロセスバリアの位置を設定することが好ましい。この時、データ競合が発生しない関数間には余計なプロセスバリアが挿入されないようにすることができる。
【００２４】
プログラム変換装置２２Ａは、データ競合判定部２３Ａおよびプロセスバリア挿入部２４Ａを備える。データ競合判定部２３Ａは、並行実行可能な関数間でデータ競合が発生するかどうかを判定する。プロセスバリア挿入部２４Ａは、データ競合が発生する関数間にプロセスバリア３０を挿入する。データ競合は、前後の関数の少なくとも一方が共有データまたは共有リソースに更新処理を実行して引き起こされる競合である。データ競合として、関数対のいずれもＷｒｉｔｅを実行するＷｒｉｔｅ／Ｗｒｉｔｅ競合と、関数対の一方がＲｅａｄを実行し、他方がＷｒｉｔｅを実行するＲｅａｄ／Ｗｒｉｔｅ競合を挙げることができる。
【００２５】
この時、関数[０]〜関数[４]は、グローバル変数に代表される共有データに対してリードまたはライトアクセスすることができる。共有リソースへのアクセスも同様に、参照（リード）または更新（ライト）アクセスに分類されるので、データ競合と共有リソース競合を明示的に区別する必要はない。
【００２６】
図２は、図１の関数間のデータ競合関係の一例を示す図である。
図２において、関数［０］〜関数［４］からアクセスされるグローバル変数ｖａｒ［０］〜ｖａｒ［５］が定義されているものとする。ここで、グローバル変数ｖａｒ［０］に対しては、関数［０］がＲｅａｄ、関数［２］がＷｒｉｔｅ、グローバル変数ｖａｒ［１］に対しては、関数［０］、関数［１］および関数［４］がＲｅａｄ、グローバル変数ｖａｒ［２］に対しては、関数［１］がＷｒｉｔｅ、グローバル変数ｖａｒ［３］に対しては、関数［０］および関数［４］がＷｒｉｔｅ、グローバル変数ｖａｒ［４］に対しては、関数［３］がＲｅａｄ、グローバル変数ｖａｒ［５］に対しては、関数［３］がＷｒｉｔｅするものとする。
【００２７】
関数の実行順序により、実行後のプログラム状態が変わるのは、少なくとも一方の関数がライト（更新）アクセスをする場合である。この時、図１のデータ競合判定部２３Ａは、関数［０］と関数［２］との間でデータ競合３５Ａが発生し、関数［０］と関数［４］との間でデータ競合３５Ｂが発生すると判定する。一方、両方の関数ともリード（参照）アクセスをする場合では、関数の実行順序によって実行後のプログラム状態が変わることはない。このため、関数[０]と関数[１]との間や、関数[１]と関数[４]との間にデータ競合が発生すると判定されることはない。
【００２８】
図３は、第１実施形態に係るプログラム変換方法を示すフローチャートである。
図３において、各関数がリード（参照）またはライト（更新）対象とする共有データまたは共有リソースを解析する（Ｓ０１）。次に、完了未確認関数リストに関数[０]を登録し、ｋ＝１に初期化する（Ｓ０２）。
【００２９】
次に、完了未確認関数リストに登録された関数のうち、関数[ｋ]とデータ競合（Ｗｒｉｔｅ／Ｗｒｉｔｅ競合またはＲｅａｄ／Ｗｒｉｔｅ競合）する関数[ｑ]（０≦ｑ＜ｋ）があるかどうか判断する（Ｓ０３）。関数[ｋ]とデータ競合する関数[ｑ]がない場合、完了未確認関数リストに関数[ｋ]を登録し（Ｓ０４）、ｋを１だけインクリメントする（Ｓ０５）。
【００３０】
一方、Ｓ０３において関数[ｋ]とデータ競合する関数[ｑ]がある場合、ｋ＝Ｎかどうか判断する（Ｓ０６）。Ｎはコア数である。図１の例では、Ｎ＝４である。ｋ＝Ｎでない場合、監視対象関数＝関数[ｑ]とするプロセスバリアを関数[ｋ]の直前に挿入する（Ｓ０７）。監視対象関数は、終了フラグ３６が監視対象とされる関数である。さらに、完了未確認関数リストから関数[ｑ]を削除し、Ｓ０５に進む。一方、Ｓ０６においてｋ＝Ｎの場合、処理を終了する。
【００３１】
ここで、監視対象関数＝関数[ｑ]とする１つ目のプロセスバリアを関数[ｋ]の直前に挿入した場合、完了未確認関数リストから関数[ｑ]を削除する。これにより、監視対象関数＝関数[ｑ]とする２つ目のプロセスバリアが、監視対象関数＝関数[ｑ]とする１つ目のプロセスバリアの後に挿入されないようにすることができる。
【００３２】
例えば、図１の関数[０]が完了未確認関数リストに登録されている時に、図２のデータ競合関係を参照することにより、関数[２]は関数[０]とデータ競合すると判断される。このため、監視対象関数＝関数[０]とするプロセスバリア３０が関数[２]の直前に挿入される。この時、完了未確認関数リストから関数[０]が削除される。このため、図２のデータ競合関係では、関数[４]は関数[０]とデータ競合する場合においても、図３のＳ０３においては、完了未確認関数リストに登録された関数のうち、関数[４]とデータ競合する関数[０]はないと判断される。このため、監視対象関数＝関数[０]とするプロセスバリアが関数[４]の直前に挿入されないようにすることができる。
【００３３】
ここで、監視対象関数＝関数[０]とするプロセスバリア３０を関数[２]の直前に挿入した場合、プロセスバリア３０は、関数[２]の実行が開始される時は、関数[０]の実行が終了していることを保証することができる。このため、関数[２]の後の関数[４]の実行が開始される時においても、関数[０]の実行が終了していることを保証することができる。この結果、関数[４]が関数[０]とデータ競合する場合においても、関数[４]の直前にプロセスバリアが挿入されないようにして、不要なプロセスバリアの挿入を防止することができる。
【００３４】
次に、計算機１Ａのプログラム並列実行処理について説明する。
図１において、計算機１Ａは、ロックフリー関数キューＬＦＱ１に基づいてプログラム並行実行を行う。計算機１Ａには、複数のコア１０〜１３、入出力インターフェース１４、ＤＲＡＭ１５およびキャッシュ１６が設けられている。計算機１Ａは、入出力インターフェース１４を介してセンサ１７およびアクチュエータ１８に接続されている。コアはＣＰＵごとに設けるようにしてもよいし、１つのＣＰＵに複数のコアが設けられていてもよい。ＤＲＡＭ１５は、コア１０〜１３からアクセス可能な共有メモリとして用いることができる。この時、各コア１０〜１３は、入出力インターフェース１４を介してＤＲＡＭ１５およびキャッシュ１６にアクセスすることができる。センサ１７は、車両の各部の状態を監視する。アクチュエータ１８は、車両のパワートレイン系、操舵系および制動系などを駆動する。
【００３５】
ＤＲＡＭ１５は、ロックフリー関数キューＬＦＱ１を保持する。また、ＤＲＡＭ１５は、各コア１０〜１３が実行する実行コードを保持することができる。ロックフリー関数キューＬＦＱ１には、計算機１Ａで並行実行可能な複数の関数が順々に登録される。ロックフリー関数キューＬＦＱ１は複数用意することができ、コア１０〜１３のいずれかが、例えば、１０ｍｓｅｃの周期でＤＲＡＭ１５に順次ロードすることができる。なお、実装の都合により、ロックフリー関数キューＬＦＱ１には、関数の実体の代わりに、関数の実体へのポインタを登録してもよい。
【００３６】
プロセスバリア３０は、データ競合する前後の関数のうち、前の関数の実行が完了するまで、後の関数の実行をプロセスバリア３０の位置で待機させる。この時、プロセスバリア３０で区切られてない関数については複数のコア１０〜１３による並行処理が可能である。例えば、関数［０］と関数［１］については、コア１０〜１３による並行処理が可能である。また、関数［２］〜関数［４］についても、コア１０〜１３による並行処理が可能である。この時、プロセスバリア３０は、データ競合する前後の関数のうち、前の関数の実行が完了したかを監視し、前の関数の実行が完了すると、後の関数を実行するコア１０〜１３の割り当てを許容する。
【００３７】
プロセスバリア３０は、指定の関数の処理完了を確認するチェッカ関数３２と、プロセスバリア３０より後の関数の実行を待機させるリミッタ関数３３とを備える。チェッカ関数３２とリミッタ関数３３とは１個ずつプロセスバリア３０に設けられ、チェッカ関数３２とリミッタ関数３３とは対をなす。リミッタ関数３３は、チェッカ関数３２の直後に配置される。チェッカ関数３２には、監視対象関数のリストが追加される。監視対象関数が複数ある場合は、それら全てのすべての監視対象関数をチェッカ関数３２に登録する。図３では、チェッカ関数３２として、プロセスバリア［０］_ｃｈｅｃｋｅｒ、監視対象関数＝関数［０］が挿入され、リミッタ関数３３としてプロセスバリア［０］_ｌｉｍｉｔｅｒが挿入された例を示した。
【００３８】
プロセスバリア３０は、関数間のデータ競合に応じてロックフリー関数キューＬＦＱ１に複数挿入することができる。これらのプロセスバリア３０を区別するため、プロセスバリア３０には、プロセスバリアＩＤ３４が付される。この時、同じプロセスバリア３０に所属するチェッカ関数３２とリミッタ関数３３は同じプロセスバリアＩＤ３４を保持する。
【００３９】
チェッカ関数３２は、指定の関数の処理完了を確認すると、チェッカ関数３２と対となるリミッタ関数３３をロックフリー関数キューＬＦＱ１から削除する。各コア１０〜１３は、プロセスバリア３０の処理時に関数の取得および実行を中断し、リミッタ関数３３の削除後に、ロックフリー関数キューＬＦＱ１から関数を取得して実行する処理を再開する。
【００４０】
ここで、指定の関数の実行の完了を監視するコアは、指定の関数を実行するコアとは別個に割り当てることができる。さらに、指定の関数を実行するコアと指定の関数の実行の完了を監視するコア以外の他のコアは、指定の関数の実行が完了するまで、プロセスバリア３０に後続する関数の実行がプロセスバリア［０］_ｌｉｍｉｔｅｒにて阻止される。
【００４１】
ロックフリー関数キューＬＦＱ１に登録されたエントリの取得に際しては、各コア１０〜１３は、ロックフリー関数キューＬＦＱ１の先頭エントリの関数を読み取る。この時、各コア１０〜１３は、ＨＥＡＤ４１とＴＡＩＬ４２という変数を参照することにより、先頭または最後の登録エントリの位置を知ることができる。ＨＥＡＤ４１とＴＡＩＬ４２は、アクセスの高速化を図るために、キャッシュ１６に保持させることができる。なお、ＨＥＡＤ４１とＴＡＩＬ４２は、ＤＲＡＭ１５が保持するようにしてもよい。そして、ＨＥＡＤ４１のアクセス回数に応じてＨＥＡＤ４１がキャッシュ１６に保持されるようにしてもよい。
【００４２】
ｍｕｔｅｘ等の排他制御機構を用いることなくデータ競合を回避し、複数のコア１０〜１３がＨＥＡＤ値とＴＡＩＬ値を更新するには、ＨＥＡＤ値とＴＡＩＬ値をアトミックに書き換え可能なＣＡＳ（ｃｏｍｐａｒｅ−ａｎｄ−ｓｗａｐ）命令を用いてロックフリー関数キューＬＦＱ１をロックフリー化することができる。ＣＡＳ命令の実行に成功したコア１０〜１３は、ロックフリー関数キューＬＦＱ１の先頭エントリを取得し、ＨＥＡＤ値を次の登録エントリに進める。ＨＥＡＤ値に対するライトアクセス競合のために、ＣＡＳ命令の実行に失敗したコア１０〜１３は、更新されたＨＥＡＤ値に対して再度ＣＡＳ命令を実行することで登録エントリを取得する。この時、複数のコア１０〜１３がＨＥＡＤ値に同時にアクセスした場合においても、必ず１つのコアはＣＡＳ命令の実行に成功し、ＨＥＡＤ値に同時にアクセスした全てのコアがＣＡＳ命令の実行に失敗することはない。このため、コア数Ｎが有限である限りは、ＣＡＳ命令の実行の失敗が際限なく何度も繰り返されるのを防止することができ、エントリ取得時の無駄時間を低減することができる。
【００４３】
このプロセスバリア３０の導入により、ロックフリー関数キューＬＦＱ１の処理に関与するコアの個数を固定する必要がなくなる。このため、各コアの実際の処理負荷に応じてロックフリー関数キューＬＦＱ１の処理に割り当てるコアの個数を動的に変えることができ、計算負荷の平準化および最悪応答時間を保証することができる。
【００４４】
また、プロセスバリア３０は、プロセスバリア３０より前の全ての関数の実行が完了しなくても、監視対象関数の実行が完了すると、プロセスバリア３０に後続する関数を実行させることができ、プロセスバリア３０に後続する関数の実行の待ち時間を減らすことができる。
【００４５】
図４は、図１のロックフリー関数キューについてのプログラム実行制御方法を示すタイミングチャートである。なお、図１および図４の例では、並行実行される関数［０］および関数［１］において、監視対象関数である関数［０］が、監視対象関数でない関数［１］より早く終了した場合を示した。
図１および図４において、並行実行可能なコアがコア１０〜１２であるものとする。ＨＥＡＤ４１は、ロックフリー関数キューＬＦＱ１の先頭エントリとして関数［０］を示しているものとする。そして、コア１０〜１２がＣＡＳ命令を実行し、コア１０がＣＡＳ命令の実行に成功したものとすると、コア１０は、ＨＥＡＤ４１が示す関数［０］を取得し、関数［０］を実行するとともに、ＨＥＡＤ４１を次の登録エントリに進める（Ｐ１０）。この時、ＨＥＡＤ４１は、ロックフリー関数キューＬＦＱ１の先頭エントリとして関数［１］を示す。
【００４６】
次に、前回ＣＡＳ命令の実行に失敗したコア１１、１２はＣＡＳ命令を再度実行し、コア１１がＣＡＳ命令の実行に成功したものとすると、コア１１は、ＨＥＡＤ４１が示す関数［１］を取得し、関数［１］を実行するとともに、ＨＥＡＤ４１を次の登録エントリに進める（Ｐ１１）。この時、ＨＥＡＤ４１は、ロックフリー関数キューＬＦＱ１の先頭エントリとしてプロセスバリア［０］_ｃｈｅｃｋｅｒを示す。また、関数［０］と関数［１］は、コア１０、１１にて並行実行される。
【００４７】
次に、前回ＣＡＳ命令の実行に失敗したコア１２はＣＡＳ命令を再度実行し、コア１２がＣＡＳ命令の実行に成功したものとすると、コア１２は、ＨＥＡＤ４１が示すプロセスバリア［０］_ｃｈｅｃｋｅｒを取得し、プロセスバリア［０］_ｃｈｅｃｋｅｒの処理を実行するとともに、ＨＥＡＤ４１を次の登録エントリに進める（Ｐ１２）。この時、ＨＥＡＤ４１は、ロックフリー関数キューＬＦＱ１の先頭エントリとしてプロセスバリア［０］_ｌｉｍｉｔｅｒを示す。
【００４８】
次に、コア１０は、関数［０］の実行を完了したものとすると、関数［０］の終了フラグ３６をｔｒｕｅに設定し、ＣＡＳ命令を実行する。そして、コア１０は、ＣＡＳ命令の実行に成功すると、ＨＥＡＤ４１が示すプロセスバリア［０］_ｌｉｍｉｔｅｒを取得し、プロセスバリア［０］_ｌｉｍｉｔｅｒの処理を実行する（Ｐ１３）。この時、コア１０は、ＨＥＡＤ４１を次の登録エントリに進めることなく、ＨＥＡＤ値をそのままにする。このため、ＨＥＡＤ４１は、ロックフリー関数キューＬＦＱ１の先頭エントリとしてプロセスバリア［０］_ｌｉｍｉｔｅｒを示したままとなる。プロセスバリア［０］_ｌｉｍｉｔｅｒの処理では、コア１０は、ロックフリー関数キューＬＦＱ１の先頭エントリを読み取り、その先頭エントリがプロセスバリア［０］_ｌｉｍｉｔｅｒである場合は、ロックフリー関数キューＬＦＱ１の先頭エントリの読み取りを繰り返す。
【００４９】
プロセスバリア［０］_ｃｈｅｃｋｅｒの処理を実行しているコア１２は、監視対象関数である関数［０］の終了フラグ３６を監視し、関数［０］の終了フラグ３６がｆａｌｓｅの場合は、関数［０］の終了フラグ３６の監視を継続する。
【００５０】
一方、コア１２は、関数［０］の終了フラグ３６がｔｒｕｅになると、プロセスバリア［０］_ｌｉｍｉｔｅｒをデキューし、プロセスバリア［０］_ｃｈｅｃｋｅｒの処理を終了する。この時、コア１２は、ＨＥＡＤ４１を次の登録エントリに進める。このため、ＨＥＡＤ４１は、ロックフリー関数キューＬＦＱ１の先頭エントリとして関数［２］を示す。
【００５１】
ＨＥＡＤ４１が、ロックフリー関数キューＬＦＱ１の先頭エントリとして関数［２］を示すと、ロックフリー関数キューＬＦＱ１の先頭エントリがプロセスバリア［０］_ｌｉｍｉｔｅｒでなくなる。この時、プロセスバリア［０］_ｌｉｍｉｔｅｒの処理を実行しているコア１０は、ロックフリー関数キューＬＦＱ１の先頭エントリを読み取ると、その先頭エントリがプロセスバリア［０］_ｌｉｍｉｔｅｒでないため、プロセスバリア［０］_ｌｉｍｉｔｅｒの処理から抜け出し、プロセスバリア３０を通過することができる。また、コア１２がプロセスバリア［０］_ｌｉｍｉｔｅｒをデキューすることにより、コア１１、１２は、プロセスバリア３０を通過することができる。
【００５２】
コア１０、１２は、プロセスバリア３０を通過すると、ＣＡＳ命令を実行する。そして、ＣＡＳ命令が成功した順序に従ってコア１０、１２は関数［２］および関数［３］を取得し、関数［２］および関数［３］を並行実行する。この時、各コア１０、１２は、ＨＥＡＤ４１の登録エントリをそれぞれ先に進める。このため、ＨＥＡＤ４１は、ロックフリー関数キューＬＦＱ１の先頭エントリとして関数［４］を示す。
【００５３】
コア１１は、コア１０、１２が関数［２］および関数［３］を実行している間も、関数［１］の実行を継続する。そして、コア１１は、関数［１］の実行が完了すると、ＣＡＳ命令を実行する。コア１１がＣＡＳ命令の実行に成功すると、コア１１は、ＨＥＡＤ４１が示す関数［４］を取得し、関数［４］を実行する。コア１１が関数［１］の実行を完了した時には、プロセスバリア［０］_ｌｉｍｉｔｅｒはデキューされている。このため、コア１１は、プロセスバリア３０による待機時間なく、関数［１］の実行に引き続いて関数［４］を実行することができる。
【００５４】
上述した第１実施形態では、コア１０による関数［０］の実行が完了すると、コア１２によってプロセスバリア［０］_ｌｉｍｉｔｅｒがデキューされる。このため、コア１０による関数［０］の実行が完了すると、コア１１による関数［１］の実行が完了しなくても、コア１０、１２は関数［２］および関数［３］を実行することができる。このため、関数［２］および関数［３］の実行を開始するまでの待ち時間を短縮することができる。
【００５５】
なお、図４において、コア１０が関数［０］の実行を完了し、関数［０］の終了フラグ３６をｔｒｕｅに設定した後、コア１０がＣＡＳ命令の実行に成功する前に、コア１２がプロセスバリア［０］_ｌｉｍｉｔｅｒをデキューした場合には、コア１０は、プロセスバリア［０］_ｌｉｍｉｔｅｒの処理（Ｐ１３）をスキップし、関数［３］を実行することができる。
【００５６】
さらに、ＣＡＳ命令の実行に成功したコア１０〜１３がＨＥＡＤ値で示される関数の実行を順次開始することで、データ競合しない関数群を並行実行しつつ、データ競合する関数対は時間分離して実行することができる。このため、ロックフリー関数キューＬＦＱ１に登録された関数をコア１０〜１３が実行するためのスケジューリング調整を不要とすることができる。
【００５７】
また、関数を実行しているコアに割込みが入り、その関数の実行の完了が遅れる場合においても、他のコアは関数の取得および実行を継続することができる。このため、関数を実行しているコアに割込みが入った場合においても、他のコアに負荷分散することができ、外部デバイスからの割込み処理に対する応答時間の抑制と負荷平準化を図ることができる。
【００５８】
図５は、図１のロックフリー関数キューの実行中に割込みが入った時のプログラム実行制御方法を示すタイミングチャートである。
図５において、例えば、関数［１］を実行しているコア１１に割込みが入り、コア１１が割込み処理を実行するため、図４に示すように、コア１１は関数［１］の実行の完了に引き続いて関数［４］を実行できないものとする。この場合においても、コア１２が関数［２］の実行を完了すると、コア１２は引き続いて関数［４］を実行することができる。このため、コア１２は、コア１１による割込み処理の完了を待たずに関数［４］の実行を開始することができ、割込み処理などの外乱負荷があった場合においても、最悪応答時間を保証することが可能となる。
【００５９】
図６は、第１実施形態に係るプログラム実行制御方法を示すフローチャートである。
図６のＳ１１において、各コア１０〜１３は、ロックフリー関数キューＬＦＱ１が空か否かを判定する。ロックフリー関数キューＬＦＱ１が空であれば処理を終了する。ロックフリー関数キューＬＦＱ１が空でなければ、Ｓ１２に進み、先頭エントリをロックフリー関数キューＬＦＱ１から読み取る。読み取ったエントリがリミッタ関数でなければ、その先頭エントリを取得し、リミッタ関数であれば返り値ｆａｌｓｅを返す。この時、リミッタ関数を示していたＨＥＡＤ値はそのまま維持し、ＨＥＡＤ値を次の登録エントリに進めない。
【００６０】
次に、Ｓ１３において、各コア１０〜１３は、ロックフリー関数キューＬＦＱ１から取得した関数がチェッカ関数３２であるか判定し、チェッカ関数３２である場合にはＳ１７に進み、チェッカ関数２２の処理１０２を実行する。チェッカ関数３２でない場合にはＳ１４に進み、各コア１０〜１３は、リミッタ関数３３であるか判定する。リミッタ関数３３である場合にはＳ２０に進み、リミッタ関数３３の処理１０１を実行する。リミッタ関数３３でない場合には、各コア１０〜１３は、Ｓ１５に進み、Ｓ１２で取得した関数を実行する。次に、Ｓ１６において、Ｓ１５で実行した関数の終了フラグ３６をｔｒｕｅにセットし、Ｓ１１に戻る。
【００６１】
チェッカ関数３２の処理１０２において、Ｓ１７では、監視対象関数の終了フラグ３６を読み出し、終了フラグ３６がｔｒｕｅであるかを判定する。終了フラグ３６がｔｒｕｅでない場合、Ｓ１７の処理を繰り返す。あるコアがチェッカ関数３２の処理１０２を実行している時に、監視対象関数を処理する他のコアが監視対象関数の実行を完了すると、監視対象関数の実行を完了したコアは、監視対象関数の終了フラグ３６をｔｒｕｅに設定する。
【００６２】
監視対象関数の終了フラグ３６が他のコアによりｔｒｕｅに設定されると、チェッカ関数３２の処理１０２を実行しているコアは、Ｓ１７において、終了フラグ３６がｔｒｕｅであると判定し、Ｓ１８に進む。なお、チェッカ関数３２に複数の監視対象関数が登録されている場合、全ての監視対象関数の終了フラグ３６がｔｒｕｅである時に、Ｓ１８に進む。Ｓ１８では、チェッカ関数３２の処理１０２を実行しているコアは、リミッタ関数３３をデキューし、Ｓ１９に進む。Ｓ１９では、チェッカ関数３２の処理１０２を実行しているコアは、チェッカ関数３２の処理を終了してＳ１１に戻る。
【００６３】
リミッタ関数３３の処理１０１において、Ｓ２０では、先頭エントリをロックフリー関数キューＬＦＱ１から読み取る。次に、Ｓ２１において、リミッタ関数３３の処理１０１を実行しているコアは、Ｓ２０で取得した関数が、Ｓ１４のリミッタ関数３３と同じプロセスバリアＩＤ３４を持つリミッタ関数３３であるかを判定する。なお、簡単のために、ロックフリー関数キューＬＦＱ１のＨＥＡＤ値を参照および比較してもよい。同じプロセスバリアＩＤ３４を持つリミッタ関数３３である場合はＳ２０に戻り、ロックフリー関数キューＬＦＱ１の先頭エントリの読み取りを繰り返す。
【００６４】
あるコアがリミッタ関数３３の処理１０１を実行している時に、チェッカ関数３２の処理１０２を実行しているコアがリミッタ関数３３をデキューすると、ロックフリー関数キューＬＦＱ１の先頭エントリは、同じプロセスバリアＩＤ３４を持つリミッタ関数３３でなくなる。このため、Ｓ２１において、リミッタ関数３３の処理１０１を実行しているコアは、Ｓ２０で取得した関数が同じプロセスバリアＩＤ３４を持つリミッタ関数３３でないと判定し、Ｓ１１に戻る。
【００６５】
これにより、チェッカ関数３２が監視対象とする関数の実行が完了した時点でリミッタ関数３３がデキューされ、Ｓ２０で行っていたループ監視処理に伴う無駄時間がなくなることから、処理の高速化を図ることができる。また、関数処理に割り当てられるコアの個数の指定は必要でなくなる。ロックフリー関数キューＬＦＱ１に登録された関数を処理している任意の時点で、そのロックフリー関数キューＬＦＱ１に登録された関数を実行するコアを追加してもよいし、いくつかのコアを別のロックフリー関数キューの処理に再割当てしてもよい。
【００６６】
図７は、第２実施形態に係るプログラム変換方法およびプログラム実行制御方法を示すブロック図である。
図７において、プログラム変換装置２２Ｂはプログラム変換処理を行う。計算機１Ｂはプログラム並行実行処理を行う。
【００６７】
まず、プログラム変換装置２２Ｂのプログラム変換処理について説明する。
プログラム変換装置２２Ｂは、並行実行可能な関数列２０を入力として、データ競合する関数対は時間分離して実行されるようにそれらの関数間にプロセスバリア５０を挿入し、ロックフリー関数キューＬＦＱ２を出力する。プロセスバリア５０は、データ競合する前後の関数のうち、前の関数の実行が完了するまで、後の関数の実行をプロセスバリア５０の位置で待機させる。この時、プロセスバリア５０は、データ競合する前後の関数のうち、前の関数の実行が完了したかを監視する。プロセスバリア５０は、ロックフリー関数キューＬＦＱ１に登録された関数を実行するＮ個のコアのうち（Ｎ−１）個以下のコアに関数の実行の完了を監視させることができる。
【００６８】
ロックフリー関数キューＬＦＱ２の各関数には、自身の関数の処理終了を示す終了フラグ５６が追加される。各関数は、自身の関数の処理が終了すると、自身の終了フラグをｔｒｕｅに設定し、自身の関数の処理が終了してない場合、自身の終了フラグをｆａｌｓｅに設定する。
【００６９】
プロセスバリア５０は、データ競合する前後の関数のうち、後の関数の直前に配置する。例えば、関数［０］と関数［２］がデータ競合３５Ａを引き起こすものとすると、プロセスバリア３０は、関数［２］の直前に挿入される。この時、プロセスバリア５０には、監視対象として関数［０］が設定される。
【００７０】
また、データ競合する前後の関数において、監視対象となる前の関数とデータ競合する後の関数が複数ある場合、後の関数のうちの最前の関数に対してのみプロセスバリアが挿入される。例えば、関数［０］と関数［２］がデータ競合３５Ａを引き起こし、関数［０］と関数［４］がデータ競合３５Ｂを引き起こすものとすると、プロセスバリア５０は、関数［２］の直前にのみ挿入され、関数［４］の直前には挿入されない。
【００７１】
プログラム変換装置２２Ｂは、データ競合判定部２３Ｂおよびプロセスバリア挿入部２４Ｂを備える。データ競合判定部２３Ｂは、並行実行可能な関数間でデータ競合が発生するかどうかを判定する。プロセスバリア挿入部２４Ｂは、データ競合が発生する関数間にプロセスバリア５０を挿入する。
【００７２】
図８は、第２実施形態に係るプログラム変換方法を示すフローチャートである。
図８において、各関数がリード（参照）またはライト（更新）対象とする共有データまたは共有リソースを解析する（Ｓ３１）。
【００７３】
次に、ｊ＝０、ｋ＝１から始めて関数[ｊ]から関数[ｊ＋ｋ]までの間でデータ競合（Ｗｒｉｔｅ／Ｗｒｉｔｅ競合またはＲｅａｄ／Ｗｒｉｔｅ競合）する関数[ｑ]（ｊ≦ｑ＜ｊ＋ｋ）があるかどうか判断する（Ｓ３２）。関数[ｊ]から関数[ｊ＋ｋ]までの間でデータ競合する関数[ｋ]がない場合、ｋを１だけインクリメントし、Ｓ３２の処理を繰り返す（Ｓ３３）。
【００７４】
一方、Ｓ３２において関数[ｊ]から関数[ｊ＋ｋ]までの間でデータ競合する関数[ｋ]がある場合、ｊ＋ｋ＝Ｎかどうか判断する（Ｓ３４）。ｊ＋ｋ＝Ｎでない場合、監視対象関数＝関数[ｑ]とするプロセスバリアを関数[ｊ＋ｋ−１]の直後に挿入し、ｊ＝ｊ＋ｋかつｋ＝１に設定して、Ｓ３２に進む。一方、Ｓ３４においてｋ＝Ｎの場合、処理を終了する。
【００７５】
次に、計算機１Ｂのプログラム並列実行処理について説明する。
図７において、計算機１Ｂは、ロックフリー関数キューＬＦＱ２に基づいてプログラム並行実行を行う。計算機１Ｂには、複数のコア１０〜１３、入出力インターフェース１４、ＤＲＡＭ１５およびキャッシュ１６が設けられている。計算機１Ｂは、入出力インターフェース１４を介してセンサ１７およびアクチュエータ１８に接続されている。
【００７６】
ＤＲＡＭ１５は、ロックフリー関数キューＬＦＱ２を保持する。ロックフリー関数キューＬＦＱ２には、計算機１Ｂで並行実行可能な複数の関数が順々に登録される。プロセスバリア５０は、データ競合する前後の関数のうち、前の関数の実行が完了するまで、後の関数の実行をプロセスバリア５０の位置で待機させる。この時、プロセスバリア５０で区切られてない関数については複数のコア１０〜１３による並行処理が可能である。例えば、関数［０］と関数［１］については、コア１０〜１３による並行処理が可能である。また、関数［２］〜関数［４］についても、コア１０〜１３による並行処理が可能である。この時、プロセスバリア５０は、データ競合する前後の関数のうち、前の関数の実行が完了したかを監視し、前の関数の実行が完了すると、後の関数を実行するコア１０〜１３の割り当てを許容する。
【００７７】
プロセスバリア５０は、並行実行可能なＮ−１個のチェッカ関数５２と１個のリミッタ関数５３とを備える。リミッタ関数５３は、最後のチェッカ関数５２の直後に配置される。例えば、並行実行可能なコアがコア１０〜１３であるものとすると、プロセスバリア５０には、３個のチェッカ関数５２と１個のリミッタ関数５３が設けられる。この時、３個のチェッカ関数５２は、４個のコア１０〜１３のうちいずれか３個のコアに割り当てることがきる。各チェッカ関数５２は、指定の関数の処理完了を確認するまでプロセスバリア５０より後の関数の実行をコアごとに待機させる。チェッカ関数５２には、監視対象関数のリストが追加される。この時、Ｎ−１個のチェッカ関数５２には、同一の監視対象関数が設定される。リミッタ関数２３は、何も処理をせず終了する空関数である。
【００７８】
図７では、チェッカ関数５２として、プロセスバリア［０］_ｃｈｅｃｋｅｒ［０］、プロセスバリア［０］_ｃｈｅｃｋｅｒ［１］およびプロセスバリア［０］_ｃｈｅｃｋｅｒ［２］が挿入され、リミッタ関数５３としてプロセスバリア［０］_ｌｉｍｉｔｅｒが挿入された例を示した。さらに、プロセスバリア［０］_ｃｈｅｃｋｅｒ［０］、プロセスバリア［０］_ｃｈｅｃｋｅｒ［１］およびプロセスバリア［０］_ｃｈｅｃｋｅｒ［２］には、監視対象関数＝関数［０］が設定されている例を示した。
【００７９】
プロセスバリア５０は、関数間のデータ競合に応じてロックフリー関数キューＬＦＱ２に複数挿入することができる。これらのプロセスバリア５０を区別するため、プロセスバリア５０には、プロセスバリアＩＤ５４が付される。この時、同じプロセスバリア５０に所属するチェッカ関数５２とリミッタ関数５３は同じプロセスバリアＩＤ５４を保持する。
【００８０】
Ｎ−１個のうちのいずれか１個のチェッカ関数５２が、指定の関数の処理完了を確認すると、チェッカ関数５２と対となるリミッタ関数５３をロックフリー関数キューＬＦＱ２から削除する。各コア１０〜１３は、プロセスバリア５０の処理時に関数の取得および実行を中断し、リミッタ関数５３の削除後に、ロックフリー関数キューＬＦＱ２から関数を取得して実行する処理を再開する。ここで、指定の関数を実行するコアＸ1以外のコアＸ2〜ＸＮは、指定の関数の実行が完了するまで、プロセスバリア５０に後続する関数の実行がプロセスバリア［０］_ｃｈｅｃｋｅｒ［０］〜プロセスバリア［０］_ｃｈｅｃｋｅｒ［Ｎ−２］にて阻止される。
【００８１】
例えば、ＨＥＡＤ４１は、ロックフリー関数キューＬＦＱ２の先頭エントリとして関数［０］を示しているものとする。そして、コア１０〜１３がＣＡＳ命令を実行し、コア１０がＣＡＳ命令の実行に成功したものとすると、コア１０は、ＨＥＡＤ４１が示す関数［０］を取得し、関数［０］を実行するとともに、ＨＥＡＤ４１を次の登録エントリに進める（Ｐ２０）。この時、ＨＥＡＤ４１は、ロックフリー関数キューＬＦＱ２の先頭エントリとして関数［１］を示す。
【００８２】
次に、前回ＣＡＳ命令の実行に失敗したコア１１〜１３はＣＡＳ命令を再度実行し、コア１１がＣＡＳ命令の実行に成功したものとすると、コア１１は、ＨＥＡＤ４１が示す関数［１］を取得し、関数［１］を実行するとともに、ＨＥＡＤ４１を次の登録エントリに進める（Ｐ２１）。この時、ＨＥＡＤ４１は、ロックフリー関数キューＬＦＱ２の先頭エントリとしてプロセスバリア［０］_ｃｈｅｃｋｅｒ［０］を示す。また、関数［０］と関数［１］は、コア１０、１１にて並行実行される。
【００８３】
次に、前回ＣＡＳ命令の実行に失敗したコア１２、１３はＣＡＳ命令を再度実行し、コア１２がＣＡＳ命令の実行に成功したものとすると、コア１２は、ＨＥＡＤ４１が示すプロセスバリア［０］_ｃｈｅｃｋｅｒ［０］を取得し、プロセスバリア［０］_ｃｈｅｃｋｅｒ［０］の処理を実行するとともに、ＨＥＡＤ４１を次の登録エントリに進める（Ｐ２２）。この時、ＨＥＡＤ４１は、ロックフリー関数キューＬＦＱ２の先頭エントリとしてプロセスバリア［０］_ｃｈｅｃｋｅｒ［１］を示す。また、関数［０］と関数［１］とプロセスバリア［０］_ｃｈｅｃｋｅｒ［０］は、コア１０〜１２にて並行実行される。この時、コア１２は、監視対象関数である関数［０］の終了フラグ５６を監視し、関数［０］の終了フラグ５６がｆａｌｓｅの場合は、関数［０］の終了フラグ５６の監視を継続する。
【００８４】
次に、前回ＣＡＳ命令の実行に失敗したコア１３はＣＡＳ命令を再度実行し、コア１３がＣＡＳ命令の実行に成功したものとすると、コア１３は、ＨＥＡＤ４１が示すプロセスバリア［０］_ｃｈｅｃｋｅｒ［１］を取得し、プロセスバリア［０］_ｃｈｅｃｋｅｒ［１］の処理を実行するとともに、ＨＥＡＤ４１を次の登録エントリに進める（Ｐ２３）。この時、ＨＥＡＤ４１は、ロックフリー関数キューＬＦＱ２の先頭エントリとしてプロセスバリア［０］_ｃｈｅｃｋｅｒ［２］を示す。また、関数［０］と関数［１］とプロセスバリア［０］_ｃｈｅｃｋｅｒ［０］とプロセスバリア［０］_ｃｈｅｃｋｅｒ［１］は、コア１０〜１３にて並行実行される。この時、コア１３は、監視対象関数である関数［０］の終了フラグ５６を監視し、関数［０］の終了フラグ５６がｆａｌｓｅの場合は、関数［０］の終了フラグ５６の監視を継続する。
【００８５】
次に、コア１０は、関数［０］の実行を完了したものとすると、関数［０］の終了フラグ５６をｔｒｕｅに設定し、ＣＡＳ命令を実行する。そして、コア１０は、ＣＡＳ命令の実行に成功すると、ＨＥＡＤ４１が示すプロセスバリア［０］_ｃｈｅｃｋｅｒ［２］を取得し、プロセスバリア［０］__ｃｈｅｃｋｅｒ［２］の処理を実行するとともに、ＨＥＡＤ４１を次の登録エントリに進める（Ｐ２４）。この時、ＨＥＡＤ４１は、ロックフリー関数キューＬＦＱ２の先頭エントリとしてプロセスバリア［０］_ｌｉｍｉｔｅｒを示す。また、関数［１］とプロセスバリア［０］_ｃｈｅｃｋｅｒ［０］とプロセスバリア［０］_ｃｈｅｃｋｅｒ［１］とプロセスバリア［０］_ｃｈｅｃｋｅｒ［２］は、コア１０〜１３にて並行実行される。
【００８６】
この時、コア１０は、監視対象関数である関数［０］の終了フラグ５６を監視し、関数［０］の終了フラグ５６がｔｒｕｅになると、プロセスバリア［０］_ｌｉｍｉｔｅｒをデキューし、プロセスバリア［０］_ｃｈｅｃｋｅｒ［２］の処理を終了する。この時、コア１２は、ＨＥＡＤ４１を次の登録エントリに進める。このため、ＨＥＡＤ４１は、ロックフリー関数キューＬＦＱ２の先頭エントリとして関数［２］を示す。
【００８７】
コア１２、１３は、関数［０］の終了フラグ５６がｔｒｕｅになると、プロセスバリア［０］_ｃｈｅｃｋｅｒ［０］およびプロセスバリア［０］_ｃｈｅｃｋｅｒ［１］の処理を終了する。この時、コア１２、１３は、プロセスバリア［０］_ｌｉｍｉｔｅｒが既にデキューされているので、プロセスバリア［０］_ｌｉｍｉｔｅｒのデキューをスキップする。プロセスバリア［０］_ｌｉｍｉｔｅｒのデキューをスキップした場合は、ＨＥＡＤ４１を次の登録エントリに進めないようにする。このため、ＨＥＡＤ４１は、ロックフリー関数キューＬＦＱ２の先頭エントリとして関数［２］を示したままとなる。
【００８８】
コア１０、１２、１３は、プロセスバリア５０を通過すると、ＣＡＳ命令を実行する。そして、ＣＡＳ命令が成功した順序に従ってコア１０、１２、１３は関数［２］、関数［３］および関数［４］を取得し、関数［２］、関数［３］および関数［４］を並行実行する。この時、コア１１は、コア１０、１２、１３が関数［２］、関数［３］および関数［４］を実行している間も、関数［１］の実行を継続する。そして、コア１１は、関数［１］の実行が完了すると、ＣＡＳ命令を実行することができる。コア１１が関数［１］の実行を完了した時には、プロセスバリア［０］_ｌｉｍｉｔｅｒはデキューされている。このため、コア１１は、プロセスバリア５０による待機時間なく、関数［１］の実行に引き続いて次の処理を実行することができる。
【００８９】
図９は、図１のプログラム変換装置のハードウェア構成例を示すブロック図である。
図９において、プログラム変換装置２２Ａには、プロセッサ１０１、通信制御デバイス１０２、通信インターフェース１０３、主記憶デバイス１０４、外部記憶デバイス１０５および出力インターフェース１０７が設けられている。プロセッサ１０１、通信制御デバイス１０２、通信インターフェース１０３、主記憶デバイス１０４および外部記憶デバイス１０５および出力インターフェース１０７は、内部バス１０６を介して相互に接続されている。主記憶デバイス１０４および外部記憶デバイス１０５は、プロセッサ１０１からアクセス可能である。
【００９０】
プロセッサ１０１は、プログラム変換装置２２Ａ全体の動作制御を司るハードウェアである。主記憶デバイス１０４は、例えば、ＳＲＡＭまたはＤＲＡＭなどの半導体メモリから構成することができる。主記憶デバイス１０４には、プロセッサ１０１が実行中のプログラムを格納したり、プロセッサ１０１がプログラムを実行するためのワークエリアを設けたりすることができる。
【００９１】
外部記憶デバイス１０５は、大容量の記憶容量を有する記憶デバイスであり、例えば、ハードディスク装置やＳＳＤ（Ｓｏｌｉｄ  Ｓｔａｔｅ  Ｄｒｉｖｅ）である。外部記憶デバイス１０５は、各種プログラムの実行ファイルやプログラムの実行に用いられるデータを保持することができる。外部記憶デバイス１０５には、データ競合判定プログラム１０５Ａおよびプロセスバリア挿入プログラム１０５Ｂを格納することができる。データ競合判定プログラム１０５Ａおよびプロセスバリア挿入プログラム１０５Ｂは、プログラム変換装置２２Ａにインストール可能なソフトウェアであってもよいし、プログラム変換装置２２Ａにファームウェアとして組み込まれていてもよい。
【００９２】
通信制御デバイス１０２は、外部との通信を制御する機能を有するハードウェアである。通信制御デバイス１０２は、通信インターフェース１０３を介してネットワーク１０９に接続される。ネットワーク１０９は、インターネットなどのＷＡＮ（Ｗｉｄｅ  Ａｒｅａ  Ｎｅｔｗｏｒｋ）であってもよいし、ＷｉＦｉなどのＬＡＮ（Ｌｏｃａｌ  Ａｒｅａ  Ｎｅｔｗｏｒｋ）であってもよいし、ＷＡＮとＬＡＮが混在していてもよい。入出力インターフェース１０７は、データ入出力機能を有するハードウェアである。
【００９３】
プロセッサ１０１がデータ競合判定プログラム１０５Ａおよびプロセスバリア挿入プログラム１０５Ｂを主記憶デバイス１０４に読み出し、データ競合判定プログラム１０５Ａおよびプロセスバリア挿入プログラム１０５Ｂを実行することにより、並行実行可能な関数間でデータ競合が発生するかどうかを判定し、データ競合が発生する関数間にプロセスバリアを挿入することができる。この時、プロセッサ１０１は、入出力インターフェース１０７を介し、プロセスバリア挿入前の関数列を取得し、その関数列の関数間にプロセスバリアが挿入されたロックフリー関数キューＬＦＱ１を出力することができる。
【００９４】
ここで、データ競合判定プログラム１０５Ａは、図１のデータ競合判定部２３Ａの機能を実現し、プロセスバリア挿入プログラム１０５Ｂは、図１のプロセスバリア挿入部２４Ａの機能を実現することができる。
【００９５】
なお、データ競合判定プログラム１０５Ａおよびプロセスバリア挿入プログラム１０５Ｂの実行は、複数のプロセッサやコンピュータに分担させてもよい。あるいは、プロセッサ１０１は、ネットワーク１０９を介してクラウドコンピュータなどにデータ競合判定プログラム１０５Ａおよびプロセスバリア挿入プログラム１０５Ｂの全部または一部の実行を指示し、その実行結果を受け取るようにしてもよい。
【符号の説明】
【００９６】
１Ａ、１Ｂ  計算機、１０〜１３  コア、１４  入出力インターフェース、１５  ＤＲＡＭ、１６  キャッシュ、１７  センサ、１８  アクチュエータ、ＬＦＱ１、ＬＦＱ２  ロックフリー関数キュー、２０  関数列、２２  プログラム変換装置、２３  データ競合判定部、２４  プロセスバリア挿入部、３０  プロセスバリア、２１、３１  関数、３２  チェッカ関数、３３  リミッタ関数、３４  プロセスバリアＩＤ、３５Ａ、３５Ｂ  データ競合、３６  終了フラグ
【図１】
2019204387.tif 000003
【図２】
2019204387.tif 000004
【図３】
2019204387.tif 000005
【図４】
2019204387.tif 000006
【図５】
2019204387.tif 000007
【図６】
2019204387.tif 000008
【図７】
2019204387.tif 000009
【図８】
2019204387.tif 000010
【図９】
2019204387.tif 000011