5

私はいくつかのコードをリファクタリングしていlockて、インスタンスコンストラクターでの使用について疑問に思っています。

public class MyClass {

    private static Int32 counter = 0;
    private Int32 myCount;

    public MyClass() {

        lock(this) {
            counter++;
            myCount = counter;
        }
    }
}

確認してください

  1. インスタンスコンストラクタはスレッドセーフです。
  2. lockステートメントは、静的な「counter」メンバーではなく、そのコードブロックへのアクセスを防ぎます。

元のプログラマーの意図が各インスタンスにその「カウント」を認識させることであった場合、「カウンター」メンバーへのアクセスを同期して、別のスレッドが新しいスレッドではないことを確認し、MyClassこのスレッドがカウント?

参考までに-このクラスはシングルトンではありません。インスタンスは、単にその数を認識している必要があります。

4

7 に答える 7

12

数を増やすだけの場合は、そのための特別なクラス(インターロック)があります...

http://msdn.microsoft.com/en-us/library/system.threading.interlocked.increment.aspx

Interlocked.Incrementメソッド

指定された変数をインクリメントし、結果をアトミック操作として格納します。

System.Threading.Interlocked.Increment(myField);

スレッド化のベストプラクティスに関する詳細情報...

http://msdn.microsoft.com/en-us/library/1c9txz50.aspx

于 2008-09-03T14:53:53.790 に答える
4

これはシングルトンパターンかそれに似たものだと思います。あなたがしたいのはあなたのオブジェクトをロックすることではなく、あなたがそれを修正している間カウンターをロックすることです。

private static int counter = 0;
private static object counterLock = new Object();

lock(counterLock) {
    counter++;
    myCounter = counter;
}

あなたの現在のコードは一種の冗長だからです。特に、コンストラクターを呼び出すことができるスレッドが1つしかないコンストラクター内にいること。これは、スレッド間で共有され、共有されている任意のスレッドからアクセスできるメソッドとは異なります。

私があなたのコードから知ることができる小さなことから、あなたはオブジェクトが作成されたときの現在のカウントをオブジェクトに与えようとしています。したがって、上記のコードを使用すると、カウンターが更新されてローカルに設定されている間、カウンターはロックされます。したがって、他のすべてのコンストラクターは、カウンターが解放されるのを待つ必要があります。

于 2008-09-03T14:33:15.353 に答える
3

別の静的オブジェクトを使用してロックすることができます。

private static Object lockObj = new Object();

このオブジェクトをコンストラクターでロックします。

lock(lockObj){}

.NETただし、 Javaの場合のようにコンパイラの最適化のために処理する必要がある状況があるかどうかはわかりません

于 2008-09-03T14:34:15.460 に答える
3

@ajmastrean

シングルトンパターン自体を使用する必要があると言っているのではなく、インスタンス化プロセスをカプセル化する方法を採用しています。

すなわち

  • コンストラクターをプライベートにします。
  • タイプを返す静的インスタンスメソッドを作成します。
  • 静的インスタンスメソッドでは、インスタンス化する前にlockキーワードを使用します。
  • タイプの新しいインスタンスをインスタンス化します。
  • カウントをインクリメントします。
  • ロックを解除して、新しいインスタンスを返します。

編集

私に起こった問題の1つは、カウントがいつ下がったかをどうやって知ることができるでしょうか。;)

もう一度編集

考えてみると、別の静的メソッドを呼び出してカウンターをデクリメントするコードをデストラクタに追加できます:D

于 2008-09-03T14:41:55.380 に答える
2

これを行う最も効率的な方法は、インターロック インクリメント操作を使用することです。カウンターをインクリメントし、静的カウンターの新しく設定された値を一度に(アトミックに)返します

class MyClass {

    static int _LastInstanceId = 0;
    private readonly int instanceId; 

    public MyClass() { 
        this.instanceId = Interlocked.Increment(ref _LastInstanceId);  
    }
}

元の例では、個々のインスタンスごとに異なる「this」参照があり、複数のインスタンスが静的メンバーを同時に更新する可能性があるため、lock(this) ステートメントは望ましい効果をもたらしません。

ある意味では、コンストラクターは、コンストラクターが完了するまで構築中のオブジェクトへの参照が表示されないため、スレッド セーフであると見なすことができますが、静的変数を保護するには何の役にも立ちません。

(Mike Schall が最初にインターロック ビットを持っていた)

于 2008-09-03T15:42:48.040 に答える
0

シングルトンパターンを変更してカウントを含めると(明らかにスレッドセーフな方法を使用して)、問題はないと思います:)

編集

クラップ誤って削除してしまいました!

インスタンスコンストラクターがスレッドセーフであるかどうかはわかりません。これについてはデザインパターンブックで読んだことを覚えています。純粋にこれが原因で、インスタンス化プロセス中にロックが設定されていることを確認する必要があります。

于 2008-09-03T14:35:45.050 に答える
0

@ロブ

参考までに、このクラスはシングルトンではない可能性があります。さまざまなインスタンスにアクセスする必要があります。彼らは単にカウントを維持する必要があります。シングルトンパターンのどの部分を変更して、「カウンター」インクリメントを実行しますか?

または、ロックを使用してカウンターをインクリメントおよび読み取るコードへのアクセスをブロックする構造の静的メソッドを公開することを提案していますか。

public MyClass {

    private static Int32 counter = 0;
    public static MyClass GetAnInstance() {

        lock(MyClass) {
            counter++;
            return new MyClass();
        }
    }

    private Int32 myCount;
    private MyClass() {
        myCount = counter;
    }
}
于 2008-09-03T14:37:43.750 に答える