Ada 202x (18日目) - pragma Conflict_Check_Policy¶
引き続きスレッド検証。
これまでのあらすじ¶
parallel
により簡単に並列化できるようになったため、並列化まわりの検証が重要になっています。
(繰り返し。)
アクセスの競合もよく起きるバグです。
parallel
によってものすごく簡単に問題のあるコードが書けてしまいます。
declare
X : Integer := 100;
begin
parallel do
X := X + 1000_000;
and
X := X - 10;
end do;
競合の有名な例え話で銀行口座に百万円振り込んだと同時に10円引き落とされたらというのがあります。 「上側/下側での読み取り」「上側の書き込み」「下側の書き込み」の順番で実行されてしまいますと口座には90円しか残らなくなります。
最近のCPUでは投機実行でもっと謎な挙動になることも考えられます。
Ada 202xでの改善¶
Ada 202xではアクセスの競合に対してかなり気合の入った検証が行われます。
pragma Conflict_Check_Policy¶
大枠としては pragma Conflict_Check_Policy
を用いてチェックを有効にしますと parallel
の各分岐や task
間で変数へのアクセスが競合しているかどうかがコンパイル時に検証されるというものです。
declare
pragma Conflict_Check_Policy (All_Conflict_Checks);
A, B : Integer := 0;
begin
parallel do
A := B + 2;
and
B := A + 3; -- error
end do;
検証の仕組みとしては各分岐ごと各変数ごとに読み取り(in)と書き込み(out)のアクセスがされているかどうかが調べられ、それが衝突しているかどうかがチェックされます。
この例では parallel
の上側では A
がout、B
がinです。
下側では A
がin、B
がoutです。
out同士またはinとoutは衝突します。
最初の例でも両方の側で X
に対してin out両方のアクセスがされていますので衝突します。
これを修正するには変数へのアクセスを protected
やランデブーの中で行うようにします。
declare
pragma Conflict_Check_Policy (All_Conflict_Checks);
protected Prot is
procedure Add (Offset : in Integer);
private
X : Integer := 100;
end Prot;
protected body Prot is
procedure Add (Offset : in Integer) is
begin
X := X + Offset;
end Add;
end Prot;
begin
parallel do
Prot.Add (1000_000);
and
Prot.Add (-10);
end do;
これで上側と下側のどちらが先に実行されても口座の残高は同じになります。
どの変数にアクセスしているかという情報はサブプログラムの外に伝播します。
Add
が protected
ではない単なるサブプログラムですとソースコード上では一箇所からしかアクセスしていないように見えてもやはりエラーになります。
declare
pragma Conflict_Check_Policy (All_Conflict_Checks);
X : Integer := 100;
procedure Add (Offset : in Integer) is -- Xにin outアクセス
begin
X := X + Offset;
end Add;
begin
parallel do
Add (1000_000);
and
Add (-10); -- error
end do;
他の要素で排他制御が行える場合やロックフリーなアルゴリズムを使いたいときは邪魔になりますので No_Conflict_Checks
等を指定してチェックを行わないようにできます。
翻訳単位を跨ぐと見えない変数が出てくるのではないか、抽象型はどうなっているのか、変数以外も競合するのでは等の疑問があるとは思います。 そちらはまた後日。 (小出し。)
関連AI¶
AI12-0267-1 Data race and non-blocking checks for parallel constructs
AI12-0298-1 Revise the conflict check policies to ensure compatibility