私が持っていると仮定struct
一定:(class
部材としての)ヒープ上に割り当てられ、そしてIは、読み取り、書き込みスレッドの数を有しているC#の値型パラメータコピースレッドセーフ
struct Foo{}
それはstruct
です。私は特定の関数に変数を渡す場合 :
void Bar(Foo param);
paramがそのstruct
のコピーとなります。 コピー操作自体はスレッドセーフですか?
私が持っていると仮定struct
一定:(class
部材としての)ヒープ上に割り当てられ、そしてIは、読み取り、書き込みスレッドの数を有しているC#の値型パラメータコピースレッドセーフ
struct Foo{}
それはstruct
です。私は特定の関数に変数を渡す場合 :
void Bar(Foo param);
paramがそのstruct
のコピーとなります。 コピー操作自体はスレッドセーフですか?
デフォルトでは、操作はスレッドセーフであると想定しないでください。例えば
には、以下のTypes
を考慮してください。
public class A
{
public B b;
}
public struct B
{
public int a;
public int b;
public int c;
public int d;
}
と、次の方法:
public static void Func(B b)
{
Console.WriteLine($"{b.a}, {b.b}, {b.c}, {b.d}");
}
次Main
の方法があり、しばらく後にコンソールを一時停止する場合:
A a = new A();
new Thread(() =>
{
while (true)
{
a.b.a = 5;
a.b.b = 5;
a.b.c = 5;
a.b.d = 5;
}
}).Start();
while (true)
{
a.b.a = 1;
a.b.b = 2;
a.b.c = 3;
a.b.d = 4;
Func(a.b);
}
structs
の一部が1
,2
,3
,4
および5
の間に混在していることがわかります。
32ビットを超えるタイプのプリミティブ演算は、x86
マシンではアトミックではなく、64ビットと同じで、x64
と同じです。マルチコアプロセッサからint
を操作
、のは言わせて、2つのスレッドから++someInt
、それがコンパイルされていても:これはあなたがたとえば、安全でしょうint
上の任意の操作を使用することができることを意味していること
ありませんinc
x86
命令では、次のことが起こります。
someInt
は9someInt
を取るです。someInt
を受け取ります。someInt
を2倍にして、まだそれはバスをロックし、コアは、関連するキャッシュの排他的所有権を持っていることを確認しますどのlock inc
にコンパイルされます代わりに、例えばInterlocked
を使用して10
に等しいです。
int
以上のコピー操作はスレッドセーフではありません(これは一度にフェッチされるため、その値を妨げるものはありません)。
4バイトを超える値を取ると、値が4バイトずつ取り込まれ、それらの操作の間に別のスレッドが値の一部を変更する可能性があります。
たとえば、ローディングlong
は、32ビットマシンでは別のスレッドが上書きしてから半分の古い値ともう半分の新しい値を読み取るため、スレッドセーフではありません。
これらはすべて4バイト以上を取る場合も構造体の略です。
コードが64ビットプロセスでのみ実行されることがわかっている場合、64ビットコピーはスレッドセーフであると考えることは有効です。ライブラリが64ビットのみであるか、または64ビットプロセスでコードが実行されていることが検出された高速パスのみを64ビットにしています。 –
逆に、32ビットのコピーであっても、32ビットアライメントでないとスレッドセーフではありませんが、パラメータコピーには適用されません。 –
これは、コードが64ビットとしてコンパイルされることを前提としています。それはコンパイラスイッチによって制御されるので、私はそれに頼ることをお勧めしません。 –
Downvoter私の答えを改善することができますので説明してください。 –
私は同意します。私は議論のないdownvoteも持っています。私たちは間違っているかもしれませんが、それを明確にすべきです。 –