3

一部のスレッドがロックmyListインしSomeMethodA、内部のブロックを実行しているときにlock、他のスレッドが実行できるかmyList.Add(1)SomeMethodBまたは「myList」がロックインされているために待機しSomeMethodAますか?

class A
{
    private List<int> myList;

    public void SomeMethodA()
    {
       lock(myList)
       {
          //...
       }
    }

    public void SomeMethodB()
    {
       myList.Add(1);
    }
}
4

4 に答える 4

6

明示的な回答の編集:いいえ、リストを明示的にロックする必要がありますSomeMethodB。コンパイラは自動的にロックを追加しません

  • それ以外の場合、なぜ明示的にロックする必要があるのでしょうか。
  • 物事はひどく遅くなるでしょう。各オブジェクトアクセスを常にロックするよりも、マルチスレッドを禁止する方がはるかに優れています1

推奨されるイディオムは次のとおりです。

class A
{
    private List<int> myList;
    private readonly object _lockObject = new Object();

    public void SomeMethodA()
    {
       lock(_lockObject)
       {
          //...
       }
    }

    public void SomeMethodB()
    {
       lock(_lockObject)
       {
           myList.Add(1);
       }
    }
}

そのようなきめの細かいロックを公開することに注意してください(通常、ロックの下でブロック操作が発生しない限り、粗いロックを実行する必要があります)。

C#のロックは再入可能であるため SomeMethodB、ロックイン内から呼び出してSomeMethodAもデッドロックは発生しません。

プライベートロックobjectインスタンスを使用する理由を更新します。

一般に、パブリックタイプ、またはコードの制御が及ばないインスタンスをロックすることは避けてください。一般的な構成要素lock(this)、lock(typeof(MyType))、およびlock( "myLock")は、このガイドラインに違反しています。

  • lock (this)インスタンスにパブリックにアクセスできる場合は問題になります。
  • lock (typeof (MyType))MyType公的にアクセス可能な場合は問題です。
  • lock("myLock")同じ文字列を使用するプロセス内の他のコードは同じロックを共有するため、これは問題です。

ベストプラクティスは、ロックオンするプライベートオブジェクト、またはすべてのインスタンスに共通のデータを保護するプライベート静的オブジェクト変数を定義することです。

参照: http: //msdn.microsoft.com/en-us/library/c5kehkcz.aspx


1(null値、参照の更新、デッドロックなど、そのアプローチに関する他の問題は別として)

于 2012-06-04T13:00:02.757 に答える
2

オブジェクトをロックすると、アプリケーション内でオブジェクトがグローバルにロックされます。他のクラスのロックを監視することもできます(パブリックオブジェクトをロックした場合)。

ただし、サンプルコードでmyList.Add(1)は、ロックをブロック でラップしていないため、ロックを待機しません。lock

「オブジェクトのロック」または「オブジェクトのロックの取得」と言うとき、ステートメントは実際にはオブジェクトへのアクセスの防止とは何の関係もlockないため、一種の誤称です。代わりに、そのオブジェクトを「キー」として使用することにより、複数のスレッドがロックされたコードブロックに入るのを防ぎます。一度に1つのスレッドのみがキーを持つことができます。したがって、オブジェクトを「ロック」しても、すべてのスレッドは引き続きオブジェクトを自由に使用できますが、一度に1つのスレッドのみがそのオブジェクトを使用してブロックに入ることができます。lock

于 2012-06-04T13:07:44.757 に答える
1

答えはノーです。1つのスレッドが特定のオブジェクト(あなたの場合myList)のロックを取得すると、他のスレッドはこのオブジェクトのロックにアクセスできなくなり、Thread1は他のすべてのスレッドをブロックしますmyList。ロック。

あなたの例では、Thread1が実行SomeMethodA()されていて(ロックがありますmyList)、Thread2が実行SomeMethodB()されている場合(ロックを要求していない場合)、問題はなく、お互いをブロックしません

より明確にするために、以下の例を検討してください。

class A
{
    private List<int> myList;

    public void SomeMethodA()
    {
       lock (myList)
       {
           //...
       }
    }

    public void SomeMethodB()
    {
        myList.Add(1);
    }

    public void SomeMethodC()
    {
        lock (myList)
        {
            myList.Add(2);
        }
    }
}

Thread1がアクセスしようとしていますSomeMethodA()

Thread2がアクセスしようとしていますSomeMethodB()

Thread3がアクセスしようとしていますSomeMethodC()

Thread1とThread2は互いにブロックせずに実行されますがmyList、Thread3はすでにThread1によって取得されているため、ロック時にブロックされます。

于 2012-06-04T13:20:19.020 に答える
0

内部にロックを設定しない場合、のロック内SomeMethodBで実行されているスレッドがある場合でも、すべてのスレッドがそれにアクセスできますSomeMethodA。スレッドの実行を防ぐSomeMethodBには、seheのようにメソッドを実装する必要があります。

于 2012-06-04T13:04:38.097 に答える