マルチタスキング コードでのアトミック操作の定義
複数のスレッドを含むコードでは、Polyspace® Bug Finder™ を使用してデータ レースを検出したり、Polyspace Code Prover™ を使用して、保護されない可能性のある共有変数を一覧表示したりすることができます。
複数のスレッド間で共有される変数が同時アクセスから保護されるかどうかを判別するために、Polyspace はその変数に対する操作がアトミックかどうかをチェックします。
非アトミック操作
操作が非アトミックである場合、Polyspace はその操作に複数のステップが含まれると見なします。これらのステップは一緒に発生する必要がなく、他のスレッドの操作で割り込むことができます。
たとえば、次の 2 つの異なるスレッドでの 2 つの操作について考えます。
スレッド 1:
var++;この操作は、
varの読み取り、varのインクリメント、およびvarへの書き込みという 3 つのステップで発生するため非アトミックです。スレッド 2:
var = 0;varのサイズがターゲットのワード サイズより小さい場合、この操作はアトミックです。Polyspace におけるワード サイズの決定方法については、下記の詳細を参照してください。
(クリティカル セクションを使用するなどして) この 2 つの操作を保護していない場合、2 つ目のスレッドでの操作が 1 つ目のスレッドでの操作に割り込む可能性があります。その割り込みの発生が、1 つ目のスレッドにおける var のインクリメント後で、かつインクリメントされた値の書き込み前である場合、予期しない結果になる可能性があります。
Polyspace で非アトミックと見なされる操作
Code Prover は、クリティカル セッションを使用するなどして操作を保護していない限り、すべての操作を非アトミックと見なします。特定の操作をアトミックとして定義を参照してください。
Bug Finder は、操作を複数のマシン命令に解釈できる場合、その操作を非アトミックと見なします。次に例を示します。
操作は読み取りおよび書き込み両方に関わります。たとえば、
var++はvarの値の読み取り、値を 1 増加し、増加した値をvarに書き込みます。操作は 32 ビット ターゲット上の 64 ビット変数に関連します。たとえば、
操作には 2 つの手順があり、long long var1, var2; var1=var2;
var2の内容を特定のターゲットのvar1にコピーします。Polyspace は [ターゲット プロセッサ タイプ] でアトミック性を計算するためのしきい値として [ポインター] サイズを使用します。たとえば、[ターゲット プロセッサ タイプ] で
[i386]を選択した場合、[ポインター] サイズは 32 ビットであり、[Long long] および [double] のサイズはともに 64 ビットです。したがって、Polyspace は 1 つのlong longまたはdouble変数を別の変数にコピーすることを非アトミックであると見なします。ターゲット プロセッサ タイプ (-target)も参照してください。操作は関数呼び出しの戻り値を共通の変数に書き込むことに関連します。たとえば、
x=func()操作はfuncを呼び出しfuncの戻り値をxに書き込みます。
2 つの割り込み操作のうち、少なくとも 1 つが非アトミックであるデータ レースを検出するには、Bug Finder のチェッカー [データ レース] を有効にします。チェッカーに対するこの制約を取り除くには、オプション -detect-atomic-data-race を使用します。
特定の操作をアトミックとして定義
操作のグループをアトミックとして定義することが必要になる場合があります。このグループの操作は、別のスレッドまたはタスクの操作で割り込むことができません。
次のいずれかの手法を使用します。
クリティカル セクション
クリティカル セクションで操作のグループを保護します。
クリティカル セクションは特定の関数の呼び出しにより開始および終了します。事前定義されたプリミティブ型のセットを使用してクリティカル セクションを開始または終了したり、独自の関数を使用したりすることができます。
クリティカル セクション内の操作のグループは、同じクリティカル セクション内の (つまり、同じ関数で開始および終了する) 別の操作のグループに対してアトミックです。
オプション
[クリティカル セクション詳細] (-critical-section-begin -critical-section-end)を使用してクリティカル セクションを指定します。時間的に排他なタスク
特定のタスクを時間的に排他であると指定することで操作のグループを保護します。
タスクのグループが時間的に排他である場合、1 つのタスクでの操作はすべて、他のタスクでの操作に対してアトミックになります。
オプション
[時間的に排他なタスク] (-temporal-exclusions-file)を使用して時間的に排他と指定します。タスクの優先順位
特定のタスクの優先順位を上げるように指定することで操作のグループを保護します。たとえば、割り込みは周期タスクよりも優先順位が高くなっています。
以下のオプションを使用して最大 4 つの異なる優先順位を指定できます (優先順位が高い順にリスト)。
より優先順位の高いタスクでの操作はすべて、優先順位の低いタスクでの操作に対してアトミックです。Polyspace でのデータ レース検出のタスク優先順位の定義も参照してください。
割り込みを無効にするルーチン (Bug Finder のみ)
すべての割り込みを無効にして操作のグループを保護します。オプション
[すべての割り込みを無効にする] (-routine-disable-interrupts -routine-enable-interrupts)を使用します。割り込みを無効にするルーチンを呼び出した後は、割り込みを再度有効にする別のルーチンを呼び出すまで、以降の操作はすべてアトミックになります。それらの操作は、すべての他のタスクでの操作に対してアトミックです。
チュートリアルについては、マルチタスキング コードでの共有変数の保護を参照してください。
参考
周期タスク (-cyclic-tasks) | 割り込み (-interrupts) | クリティカル セクション詳細 (-critical-section-begin -critical-section-end) | 時間的に排他なタスク (-temporal-exclusions-file)