12

あるクラスに次のプロパティがあり、その目的がロックとして使用されるとします。

protected object SyncRoot { get; private set; }

とにかく、これがどのように設定されたかに関係なく。実際に設定されている場合、それを使用するためのベストプラクティスは何ですか?

null オブジェクトではロックが効かないので、このように処理すればよいのでしょうか?

lock (SyncRoot ?? new object())
    SomeMethod();

または、このように null をチェックする必要がありますか?

if (SyncRoot != null)
    lock (SyncRoot)
        SomeMethod();
else
    SomeMethod();

実際に設定されている場合は、それを使用してロックしたいと思います。そうでなければ、私は気にしません。とにかく、最初のソリューションは非効率的または冗長ですか?

編集:これらの答えはすべて良いです。ただし、1つしか選べません。Luke と話し合った私の状況を考えると、私の SyncRoot を null にする理由はありません。シングルスレッド環境でのロックのオーバーヘッドはそれほど大きくありませんが、マルチスレッド環境では必要です。

(4 人全員に投票してください) 迅速な返信ありがとうございます。

4

6 に答える 6

22

私は通常、プロパティではなくプライベートメンバー変数を使用します。

private static object MyLock = new object();

このようにして、常に初期化されます。

次のような非静的バージョンを使用することもできます

private readonly object MyLock = new object();
于 2012-08-03T02:53:11.047 に答える
13

同期中

SyncRoot ?? new object()

SyncRootisの場合null、各スレッドは毎回新しいオブジェクトを取得するため、意味がありません。new別のオブジェクトで同期しても効果はありません。他の誰も同じオブジェクトで同期できない可能性があるため、スレッドはすぐに続行されます。

SyncRoot最初のスレッドがロックを取得しようとする前に、コンストラクターで初期化する必要があります。

于 2012-08-03T03:01:09.797 に答える
4

1 つ目は、適切な同期につながらないため、問題になります。

lock (SyncRoot ?? new object())
    SomeMethod();

その理由は、新しいオブジェクトを作成して割り当てないSyncRootと、ヒープに配置されますが、それへの参照がないためです。したがって、別のスレッドが来ると、それは見つかりません... 絶対に役に立たなくなり、クリティカルセクションへのアクセスをブロックしません。

2 番目のアプローチは機能しますが、ロックが利用できる場合にのみロックを使用する理由がよくわかりません。

于 2012-08-03T03:00:01.610 に答える
3

ドキュメントから: https://msdn.microsoft.com/en-us/library/c5kehkcz.aspx

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

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

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

サンプル:

 class Account
{
    decimal balance;
    private Object thisLock = new Object();

    public void Withdraw(decimal amount)
    {
        lock (thisLock)
        {
            if (amount > balance)
            {
                throw new Exception("Insufficient funds");
            }
            balance -= amount;
        }
    }
}
于 2016-03-01T14:15:50.027 に答える
2

最善の選択肢は、ロック オブジェクトの消費者がロック オブジェクトを使用する前に、常にロック オブジェクトを初期化することです。常にロック オブジェクトを割り当てるコストは小さく、スレッドの競合がない場合はロックを取得するコストも小さくなります。

したがって、コード全体にロック/ロックなしチェックを追加すると、コードの複雑さが 2 倍になり、微妙なスレッド バグが発生する可能性がありますが、目に見えるパフォーマンス上の利点はおそらく得られません。

コードを簡素化します。常にロックを取得します。

于 2012-08-03T03:02:48.103 に答える