5

クラスとそのプロパティがあります。これらのプロパティへのアクセスは、さまざまなスレッドによって非常に頻繁に行われます。

各プロパティに同じオブジェクト(lockステートメント用)を使用する方が効率的ですか?

private readonly object padlock = new object();

private string name;
private int age;

public string Name
{
   get
   {
      lock(padlock)
         return name;
   }

   set
   {
      lock(padlock)
         name = value;
   }
}

public int Age
{
   get
   {
      lock(padlock)
         return age;
   }

   set
   {
      lock(padlock)
         age = value;
   }
}

または、プロパティごとに異なるオブジェクトを使用しますか?

private readonly object padlockName = new object();
private readonly object padlockAge = new object();

private string name;
private int age;

public string Name
{
   get
   {
      lock(padlockName)
         return name;
   }

   set
   {
      lock(padlockName)
         name = value;
   }
}

public int Age
{
   get
   {
      lock(padlockAge)
         return age;
   }

   set
   {
      lock(padlockAge)
         age = value;
   }
}

2番目のバージョンは意味がありますか?

4

2 に答える 2

4

これらのロック パターンのいずれかがアプリケーションの正確性を保証するとは思えないため、あなたが尋ねた質問に答えることさえためらっています。オブジェクト全体が一貫した状態に保たれることは保証されません。個々のプロパティが同時に更新されないようにするだけです。別の言い方をすれば、アトミックな読み取りと書き込みを遠回しに実装したということです。

たとえば、 をインクリメントする操作があるとしますAge。2 つの異なるスレッドが同時にそれを行った場合、最終結果は (Age + 1) または (Age + 2) になる可能性があります。

ほとんどの場合、オブジェクト内からロックを削除し、呼び出し元に同時実行の問題を適切に処理させる必要があります。簡単な解決策の 1 つは、オブジェクトと対話している間、オブジェクト全体をロックすることです。例えば:

lock(myObj){
  myObj.Age++;
  myObj.Name = "Bill";
}

アップデート

中間の段落をさらに詳しく説明するとAge++、2 つの異なるスレッドで実行すると異なる結果が得られる理由は、++オペレーターがアトミックではないためです。これとほぼ同等です。

int temp = Age;
temp = temp + 1;
Age = temp;

2 つのスレッドが同じことを実行した場合、次のような順序で実行できます (わかりやすくするために、一時変数の名前を変更しました)。

int temp1 = Age; //thread 1
int temp2 = Age; //thread 2
temp1 = temp1 + 1;  //thread 1
temp2 = temp2 + 1; //thread 2
Age = temp1; //thread 1
Age = temp2; //thread 2

ロックの目的は、1 つのスレッドが読み取り-インクリメント-書き込みシーケンス全体を実行してから、他のスレッドが実行するようにすることです。しかし、あなたのロックスキームはそれをしません。

于 2012-11-27T21:00:56.563 に答える