1

2 つの異なるオブジェクトを一緒にロックする方法はありますか? 使用しようとしましたが、次のlock(obj1, obj2){...}エラーが発生しました。

invalid expression term ','

更新: 多くのユーザーが 1 つのロックだけを試してみるように言ったので、ほとんどの場合はその方が望ましいため、アドバイスに感謝します。2 つのオブジェクトをロックする方が合理的だと思うケースを示したいだけです。 . 異なるスレッド間で 2 つのキューを共有する場合を考えてみましょう。do と同時に避ける必要がありEnqueue(item)ますDequeue()。ここで、コードの特定のセクションで、1 つのキューから要素を取得し、それを 2 番目のキューに挿入したいとします。私はそれが可能であることを知っています:

var itme;
lock(_lock1)
{
    item = q1.Dequeue();
    Monitor.Pulse(_lock1);
}
lock(_lock2)
{
    q2.Enqueue(item);
    Monitor.Pulse(_lock2);
}

_lock1しかし、両方をロックすると_lock2、より読みやすく、クリーンになると思います。

4

3 に答える 3

1

lock2 つ (またはそれ以上) の異なるオブジェクトで使用するための構文は次のとおりです。

lock (a) lock (b)
{
}

ただし、このタイプの使用は一般的にお勧めできません。これにはいくつかの理由があります。

  • ロックが宣言される順序は、どこでも一貫していなければなりません。そうしないと、デッドロックが発生する可能性があります。
  • ほとんどの場合、不要です。
  • コード臭です。

私の意見では、最初の理由は本当に警官です。開発中にミスを犯す可能性のある方法は無数にあります。これは数ある中の 1 つにすぎません。そして、実際には、(起こりうる他の種類の間違いと比較して) 正しいことをするのは非常に簡単です。ロックが常に同じ順序で取得されるようにしてください。さらに、ネストされたロックを使用することについて、本質的に危険なことは何もありません (これも、正しく行われている限り)。ネストされたロックは常に取得されます。ほとんどの場合、他のクラスを呼び出すことによって、または実行がさまざまなスタック フレームを介して進行するときに、暗黙的に行われます。

ここで本当に重要なのは、2 番目と 3 番目の理由です。ほとんどの場合、1 つのロックで十分であるため、コードの同じセクションで 2 つのロックを取得する必要はありません。実際、コードの同じセクションで 2 つのロックを取得する必要があったとは思いません。少なくとも明示的ではありません。それは通常、問題について間違って考えていることを意味するため、コードの匂いです。コードが複雑であるか、奇妙なコード パスを使用している可能性があります。必要なロックが 1 つだけになるようにコードを構造化すると、コードの追跡がはるかに容易になる可能性があります。

別のメモとして、ロックがどのように機能するかについて混乱しているのではないかと思います. キーワードで使用されているオブジェクト インスタンスlockが同時アクセスから保護されていると考えているなら、それは間違いです。それはlockキーワードの仕組みではありません。によって参照されるオブジェクトは、同じオブジェクト参照lockでマークされた別の (または同じ) セクションと同時に実行されないことが保証されているコードのクリティカル セクションをマークすることを目的としています。

アップデート:

私はあなたの例を見て、最初に飛び出したのは、このコードがスレッドセーフではないかもしれないということです. ただし、関連する完全なコンテキストはわかりません。私が見ているのは、この架空のクラスが内部で 2 つのキューを使用しており、2 つの異なるロックをパルスしているということだけです。ある程度の推測はできますが、間違っているかもしれません。単一のクラス内でそのようなことを行う状況を想像するのに苦労しています。しかし、そうは言っても、このコードを実行するスレッドがロック間でプリエンプトされるとどうなるか考えたことはありますか? これは、クラスが中途半端な状態になるチャンスです (アイテムはどちらのキューにもありません)。別のスレッドがこのクラスを使用しようとするとどうなりますか? アイテムがぶら下がっている状況をうまく処理できますか? さらにコメントするには、さらに多くのコードを確認する必要があります。

于 2013-09-26T14:58:02.620 に答える
1

これを試して

lock(obj1)
{
   lock(obj2)
   {
        // here you have lock on obj1 and obj2
   }
}

lock は引数を 1 つだけ受け入れます。上記の例は、2 番目のロックの範囲内で 2 つのアイテムをロックします。

多分それは質問への答えを提供していますが、:

ここでのロックは、ロックの期間中、他のスレッドの他のコードがオブジェクトにアクセスしたり変更したりできないという意味ではありません。オブジェクトをロックすると、他のスレッドが同時にオブジェクトを変更できます。ロック コード ブロックでできることは、ロック ブロック内のコードを単一のエントリにすることです。つまり、1 つのスレッドだけがロック コード ブロックを 1 回実行でき、同じコード ブロックを実行しようとする他のスレッドは、所有者が実行されるまで待機する必要があります。スレッドは、コード ブロックの実行で完了します。したがって、基本的に、通常は 2 つ以上のオブジェクトをロックする必要はありません。あなたの目的をロックすることは、コードブロックを単一のエントリにすることです

要するに、他の人が述べたように、このソリューションは役に立たないので、ロックに必要な新しいオブジェクトを作成することをお勧めします。

于 2013-09-26T11:44:25.867 に答える