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