私はこれをよく見ます:
object lockObj;
List<string> myStrs;
// ...
lock(lockObj)
{
myStrs.Add("hello world");
}
なぜ別のオブジェクトがあるのですか?確かにこれを行うことができます:
List<string> myStrs;
// ...
lock(myStrs)
{
myStrs.Add("hello world");
}
私はこれをよく見ます:
object lockObj;
List<string> myStrs;
// ...
lock(lockObj)
{
myStrs.Add("hello world");
}
なぜ別のオブジェクトがあるのですか?確かにこれを行うことができます:
List<string> myStrs;
// ...
lock(myStrs)
{
myStrs.Add("hello world");
}
リストが公開されている場合にのみリストを直接ロックするのは問題でmyStrs
あり、他の呼び出し元もロックできるため、デッドロックが発生する可能性があります。
private メンバーであれば問題ないはずですが、セパレートでロックするのobject
は、いずれにしても良い習慣です。
より詳細な回答については、この同様の質問を参照してください: なぜロック(これ) {...} が悪いのですか?
一般に、パブリックタイプ、またはコードの制御が及ばないインスタンスをロックすることは避けてください。一般的な構成要素lock(this)、lock(typeof(MyType))、およびlock( "myLock")は、このガイドラインに違反しています。
- インスタンスにパブリックにアクセスできる場合、ロック(これ)は問題になります。
- MyTypeがパブリックにアクセス可能な場合、lock(typeof(MyType))は問題になります。
- 同じ文字列を使用するプロセス内の他のコードは同じロックを共有するため、lock(“ myLock”)は問題です。
ベストプラクティスは、ロックオンするプライベートオブジェクト、またはすべてのインスタンスに共通のデータを保護するプライベート静的オブジェクト変数を定義することです。
ドキュメントロックを形成するc#
リストをロックオブジェクトとして使用し、それがnullにリセットされた場合、lock(myStringList)はArgumentNullExceptionをスローします。コンソールアプリケーションの簡単なテストコードの下。
private static IList<string> mystringList = new List<string>();
static void Main(string[] args)
{
new Thread(() =>
{
try
{
while (true)
{
//Acquire the lock
lock (mystringList)
{
//Do something with the data
Thread.Sleep(100);
Console.WriteLine("Lock acquired");
}
}
}
catch (Exception exception)
{
Console.WriteLine("Exception: " +exception.Message);
}
}).Start();
new Thread(() =>
{
//Suppose we do something
Thread.Sleep(1000);
//And by some how reset the list to null
mystringList = null;
}).Start();
Console.ReadLine();
}
アイデアは、見ているコードだけがアクセスできるプライベート メンバーを常にロックすることです。一方、パブリック メンバーなどの制御できないメンバーをロックすると、コードの他の部分が既にロックを保持している可能性があります。これにより、予期しないブロッキング動作が発生する可能性があります。
したがって、これは、特にロック用のプライベートオブジェクトを持つという経験則/ベストプラクティスにつながったと思います。
他にも理由があるかどうか見てみたいと思います。
文字列のリストは、内部実装の詳細に使用されるリストです。
文字列リストを再初期化するような方法で実装を変更すると、2 番目のバージョンの問題が発生する可能性があります。
次に、実装のスレッドセーフが壊れる可能性があります。
したがって、同期には別のオブジェクトを使用し、このオブジェクトを読み取り専用として宣言することをお勧めします。