私はC#でマルチスレッドキャッシュを構築しています。これはCarオブジェクトのリストを保持します。
public static IList<Car> Cars {get; private set;}
ロックせずにスレッド内の参照を変更しても安全かどうか疑問に思っていますか?
例えば.
private static void Loop()
{
while (true)
{
Cars = GetFreshListFromServer();
Thread.Sleep(SomeInterval);
}
}
基本的に、Carsへの新しい参照の割り当てがアトミックであるかどうかにかかっています。
そうでない場合は、明らかに自分の車にプライベートフィールドを使用し、取得と設定をロックする必要があります。
はい、参照の更新は言語仕様でアトミックであることが保証されています。
5.5変数参照のアトミシティ
次のデータ型の読み取りと書き込みはアトミックです:bool、char、byte、sbyte、short、ushort、uint、int、float、および参照型。さらに、前のリストの基になるタイプを持つenumタイプの読み取りと書き込みもアトミックです。 long、ulong、double、decimalなどの他のタイプの読み取りと書き込み、およびユーザー定義タイプは、アトミックであることが保証されていません。
ただし、タイトなループ内では、可能性がありますレジスタキャッシュによって噛まれます。この場合、メソッド呼び出しがインライン化されていない限り(発生する可能性があります)、ほとんどありません。個人的には、lock
を追加してシンプルで予測可能にしますが、ここでもvolatile
が役立ちます。また、完全なスレッドセーフは単なる原子性以上のものであることに注意してください。
キャッシュの場合、私はInterlocked.CompareExchange
を個人的に調べます。つまり、tryを更新しますが、失敗した場合はやり直しを行います。作業最初から(新しい値から開始)そして再試行します。
@Marc Gravellの回答では、C#言語仕様5.5で参照されているように、「ユーザー定義型」という用語の意味を理解することが重要です。私は明確な定義を見つけていませんw.r.t. C#言語仕様でのこの使用法。 UMLおよび一般的な用語では、クラスはタイプのインスタンスです。しかし、C#言語仕様のコンテキストでは、その意味は明確ではありません。
Visual Basic言語リファレンスセクション「ユーザー定義タイプ」( https://msdn.Microsoft.com/en-us/library/cec05s9z.aspx )は次のように述べています。
「以前のバージョンのVisualBasicは、ユーザー定義型(UDT)をサポートしています。現在のバージョンは、UDTを構造に拡張します。」
したがって、ユーザー定義型はクラスではなく構造体であるように見えます。
だが ....
「C#プログラミングガイド」セクションの「タイプ」( https://msdn.Microsoft.com/en-us/library/ms173104.aspx )によると:
「典型的なC#プログラムは、クラスライブラリの型とユーザー定義の型を使用します」
これは、クラスがユーザー定義型であることを意味します。後で、「複雑なユーザー定義タイプ」の例を示します。
MyClass myClass;
これは、「MyClass」がユーザー定義型であることを意味します。そして後でそれは言う:
「CTSの各型は、値型または参照型として定義されます。これには、.NET Frameworkクラスライブラリ内のすべてのカスタム型と、独自のユーザー定義型も含まれます。 。 "
...これは、開発者によって作成されたすべてのクラスが「ユーザー定義型」であることを意味します。
そして最後に、この用語の意味が決定的に議論されていないこのStackoverflowアイテムがあります: プロパティがC#でユーザー定義型であるかどうかを判断するにはどうすればよいですか?
したがって、安全のために、作成したクラスまたは.Net Frameworkで見つかったクラスのすべてをユーザー定義型と見なす必要があります。したがって、C#で記述されているため、割り当てに対してスレッドセーフではありません。言語仕様セクション5.5:
...の読み取りと書き込み、およびユーザー定義型は、アトミックであることが保証されていません。
口語的な用語がC#言語仕様のような正確な仕様で使用されているのは残念です。このあいまいさのために、スレッドセーフにするために、「ユーザー定義型」にCLRクラスが含まれていないことが判明した場合よりも最適ではないコードを記述している可能性があります。
したがって、回答の現在の根拠がこの重大なあいまいさを残しているため、このスタックオーバーフローの回答をさらに明確にするよう求めています。現状では、「参照割り当てはスレッドセーフですか?」という質問に対する答えは「[〜 #〜]いいえ[〜#〜] "。