実行システムと優先度の使用について
- 更新日2025-08-27
- 10分で読める
通常のアプリケーションでは、標準実行システムでVIのマルチタスクを自動的に処理するため、それ以外の実行システムや優先度を使用する必要はありません。デフォルトで、すべてのVIは標準実行システムでは優先度「低」で実行されます。マルチスレッド処理のアプリケーションでは、別のスレッドがユーザインタフェースの動作を処理します。したがって、VIはユーザインタフェースの操作から隔離されています。シングルスレッドのアプリケーションでは、実行システムはユーザインタフェースの操作とVIの実行の間で切り替えを行い、似たような結果となります。
一般に、実行に優先度を与える方法として一番良いのは、待機関数を使用してアプリケーション内の優先度の低いループを遅くすることです。100~200 msの遅延はユーザがほとんど気付かない程度であるため、これは特にユーザインタフェースVIのループで役に立ちます。
優先度を使用する場合には、慎重に使用してください。長時間実行される優先度の高いVIを設計する場合、これより優先度の低いタスクと時間を共有するように、これらのVIの比較的タイムクリティカルでないコードのセクションに待機を追加することを検討してください。
グローバル変数やローカル変数など、他のタスクが変更する外部リソースは、慎重に扱ってください。機能的グローバル変数またはセマフォなどの同期テクニックを使用して、これららのリソースへのアクセスを保護します。
グローバル変数、ローカル変数および外部リソースに対する同期アクセス
実行システムはいくつかのタスクを並列に行うため、グローバル変数、ローカル変数、およびリソースが適切な順序でアクセスされることを確認する必要があります。
競合状態を回避する
対処方法はいくつかありますが、このうちの1つを使用して競合状態を回避することができます。最も簡単な方法は、グローバル変数が変更される箇所をアプリケーション全体で1つしか持たないことです。
シングルスレッド処理のアプリケーションでは、優先度がサブルーチンのVIを使用して、競合が発生しないようにグローバル変数の読み書きを行うことができます。これは、優先度がサブルーチンのVIは他のどのVIとも実行スレッドを共有しないためです。マルチスレッド処理のアプリケーションでは、別のスレッドで実行する他のVIがグローバル変数に同時にアクセスできるため、優先度がサブルーチンのVIはグローバル変数への排他的アクセスを保証しません。
機能的グローバル変数
機能的グローバル変数は、初期化しないシフトレジスタ内でループを使用してグローバルデータを保持する再入可能ではないVIです。通常、グローバル変数にはVIがどのタスクを実行するかを指定する動作入力パラメータがあります。機能的グローバル変数を使用して変数の動作にアクセスするコードのクリティカルセクションを保護することができます。これによりグローバル変数に関する競合を回避することができます。グローバル変数を使用すると、変数の値を読み取ってその値を変更した後で変数に書き込むと、同時に同じ変数を読み込む2つの並列のコードが互いの変更を上書きし合うため競合状態が発生します。機能的グローバル変数を使用するとデータを変更する動作を保護できます。たとえば、機能的グローバル変数はメモリを読み取り、増分、書き込む動作またはデータベースを更新またはファイルを変更する動作を含むクリティカルセクションにおける競合状態を防止します。
以下の図は、簡単なカウントを行うグローバル変数を実装する機能的グローバル変数を示します。初期化されていないシフトレジスタのWhileループを使用して、操作の結果を保持します。この例の動作は、初期化、読み取り、増分、および減分です。
VIを呼び出すごとに、ループのブロックダイアグラムは一回だけ実行します。動作パラメータに従って、ループ内のケースはシフトレジスタの値の初期化を行ったり、変更しなかったり、増分、減分を行います。
上記の例のように、機能的グローバル変数は、簡単なグローバル変数を実装するために使用できますが、スタックやキューのバッファのような複雑なデータストラクチャの実装には特に便利です。また、グローバル変数で表すことができないファイル、計測器、データ収集デバイスのようなグローバルリソースへのアクセスを保護するために機能的グローバル変数を使用することもできます。機能的グローバル変数の呼び出しは、VIを再入可能に設定しない限り独立して実行されます。
通常、同期に関する問題は機能的グローバル変数で解消することができます。これは、機能的グローバルVIによって、それに含まれるデータの変更は一つの発呼者ずつでしかできなくなるためです。機能的グローバル変数の欠点の一つは、保持されるリソースを修正する方法を変更する場合に機能的グローバルVIのブロックダイアグラムを変更して新しい動作を追加しなければならないことです。グローバルリソースの使用に関して頻繁に変更を行うアプリケーションでは、変更作業に手間がかかります。そのような場合は、セマフォを使用してグローバルリソースへのアクセスを保護するアプリケーションを設計してください。
セマフォ
セマフォ (別名ミューテックス) は、グローバル変数などの共有リソースへのアクセスを保護するために使用します。共有リソースにアクセスするコードは、クリティカルセクションと呼ばれます。セマフォは、同時にセマフォへアクセスできるタスク数を特定数のみにすることで、クリティカルセクションへのアクセスを保護します。通常、共通のセマフォで保護されたクリティカルセクションには一度に1つのタスクだけがアクセスすることが望まれます。ただし、事前に定義した制限を超えない範囲で1つ以上のタスクがクリティカルセクションにアクセスできるようセマフォを構成することができます。
一般に、セマフォを使用する際は以下の手順に従う必要があります。
- コード内のクリティカルセクションの特定―セマフォは通常、共有リソースにアクセスするコード部分へのアクセスを制御するために使用します。たとえば、複数のサブVIが1つのグローバル変数を使用する場合、競合状態を回避するためには、それらのコード部分が同時に実行されないよう保証する必要があります。このような場合、そのグローバル変数を読み書きする各セクションがコードのクリティカルセクションとなります。クリティカルセクションを含むコードの例には、ファイルI/OおよびデバイスI/Oが挙げられます。
- クリティカルセクションによって共有されるセマフォの作成―「セマフォリファレンス取得」VIを使用して、新しいセマフォを作成するか、名前を指定して既存のセマフォを取得します。新しいセマフォは、デフォルトでは1度に1つのタスクによる取得が可能です。1つのセマフォに複数のタスクが同時にアクセスできるよう構成するには、「セマフォリファレンス取得」VIのサイズ入力で適切なタスク数を指定します。
- 各クリティカルセクションの前にセマフォへのアクセスを取得―「セマフォ取得」VIを使用してセマフォへのアクセスを要求します。別のタスクがセマフォを使用している場合、そのタスクがセマフォを解放するまで「セマフォ取得」VIでデータフローが一時停止します。コードセクションがセマフォを取得すると、他のタスクはそのコードが解放するまでセマフォを取得できません。したがって、「セマフォ取得」VIと「セマフォ解放」VIの間で保護されたコードは、他の保護セクションが実行を開始する前に確実に完了します。
- 各クリティカルセクションの前にセマフォへのアクセスを取得―セマフォを待機している別のタスクがセマフォを取得し、そのコードのクリティカルセクションを実行できるように、「セマフォ解放」VIを使用してセマフォへのアクセスを解放します。
- セマフォのリファレンスを解放―「セマフォリファレンス解放」VIを使用して、セマフォのリファレンスを解放します。システムリソースを効率的に使用するために、セマフォを使用したタスクがすべて終了したことが確実なときにはセマフォのリファレンスを必ず解放してください。
「セマフォリファレンス取得」VIと「セマフォリファレンス解放」VIを使用したサンプルは、labview\examples\Synchronization\SemaphoreのSimple Semaphore VIを参照してください。
以下の図は、セマフォを使用して重要なセクションを保護する方法を示します。別のVIがセマフォを作成し、そのリファレンスを以下のサブVIに渡します。セマフォのサイズは1なので、一度に1つのタスクしかこのセマフォにアクセスできません。
上のブロックダイアグラムには、それぞれ同じグローバル変数、カウントにアクセスするクリティカルセクションが含まれています。このため、これらのブロックダイアグラムは同じセマフォを共有します。どちらかのブロックダイアグラムがそのクリティカルセクションを実行する前に、ブロックダイアグラムは他のブロックダイアグラムがセマフォを既に取得しているかを検知するために「セマフォ取得」VIを呼び出します。セマフォがビジー状態の場合、「セマフォ取得」VIはセマフォが使用可能になるまで待機します。セマフォが使用可能になると、「セマフォ取得」VIは、ブロックダイアグラムがクリティカルセクションを実行する許可があることを示すタイムアウトFALSEを返します。ブロックダイアグラムがクリティカルセクションの実行を終了すると、「セマフォ解放」VIはセマフォを解放して、待機している別のブロックダイアグラムに実行を再開することを許可します。
セマフォの寿命
アイドル状態ではないトップレベルのVIがセマフォのリファレンスを所有している限り、セマフォはメモリに残ります。トップレベルVIがアイドル状態になると、トップレベルVIのサブVIに存在するリファレンスを含む、VIが所有するすべてのセマフォのリファレンスが解放されます。名前付きのセマフォへの最後のリファレンスが解放されると、セマフォは破棄されます。名前が付けられていないセマフォに対して1つのリファレンスのみしか取得できないため、トップレベルVIが待機状態になると、名前のないセマフォは破棄されます。複数のトップレベルVIを介してセマフォを使用するには、セマフォに名前を付けて、各VIでセマフォの固有リファレンスを取得できるように、各トップレベルVIから「セマフォリファレンス取得」VIを呼び出します。