Frage

Ich überarbeite Code und frage mich, ob a lock im Instanzkonstruktor.

public class MyClass {

    private static Int32 counter = 0;
    private Int32 myCount;

    public MyClass() {

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

Bitte bestätigen

  1. Instanzkonstruktoren sind threadsicher.
  2. Die Sperranweisung verhindert den Zugriff auf diesen Codeblock, nicht auf das statische „Zähler“-Mitglied.

Wenn die Absicht des ursprünglichen Programmierers darin bestünde, dass jede Instanz ihre „Anzahl“ kennt, wie würde ich dann den Zugriff auf das „Zähler“-Mitglied synchronisieren, um sicherzustellen, dass kein anderer Thread neu ist? MyClass und die Zählung ändern, bevor diese ihre Zählung festlegt?

Zu Ihrer Information: Diese Klasse ist kein Singleton.Instanzen müssen lediglich ihre Anzahl kennen.

War es hilfreich?

Lösung

@ajmastrean

Ich sage nicht, dass Sie das Singleton-Muster selbst verwenden sollten, sondern dessen Methode zur Kapselung des Instanziierungsprozesses übernehmen sollten.

d.h.

  • Machen Sie den Konstruktor privat.
  • Erstellen Sie eine statische Instanzmethode, die den Typ zurückgibt.
  • Verwenden Sie in der statischen Instanzmethode vor der Instanziierung das Schlüsselwort lock.
  • Instanziieren Sie eine neue Instanz des Typs.
  • Erhöhen Sie die Anzahl.
  • Entsperren Sie die neue Instanz und geben Sie sie zurück.

BEARBEITEN

Ein Problem ist mir aufgefallen: Wie würden Sie wissen, wann die Zählung gesunken ist?;)

NOCHMALS BEARBEITEN

Wenn Sie darüber nachdenken, könnten Sie dem Destruktor Code hinzufügen, der eine andere statische Methode aufruft, um den Zähler zu dekrementieren :D

Andere Tipps

Wenn Sie nur eine Zahl erhöhen, gibt es genau dafür eine spezielle Klasse (Interlocked) ...

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

Interlocked.Increment-Methode

Erhöht eine angegebene Variable und speichert das Ergebnis als atomare Operation.

System.Threading.Interlocked.Increment(myField);

Weitere Informationen zu Best Practices für das Threading ...

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

Ich vermute, dass es sich hierbei um ein Singleton-Muster oder ähnliches handelt.Sie möchten Ihr Objekt nicht sperren, sondern den Zähler sperren, während Sie es ändern.

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

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

Weil Ihr aktueller Code irgendwie überflüssig ist.Insbesondere im Konstruktor, wo es nur einen Thread gibt, der einen Konstruktor aufrufen kann, im Gegensatz zu Methoden, bei denen er von mehreren Threads gemeinsam genutzt werden kann und auf die von jedem gemeinsam genutzten Thread aus zugegriffen werden kann.

Soweit ich aus Ihrem Code ersehen kann, versuchen Sie, dem Objekt zum Zeitpunkt seiner Erstellung die aktuelle Anzahl zu geben.Mit dem obigen Code wird der Zähler gesperrt, während der Zähler aktualisiert und lokal eingestellt wird.Alle anderen Konstrukteure müssen also auf die Freigabe des Zählers warten.

Sie können ein anderes statisches Objekt verwenden, um es zu sperren.

private static Object lockObj = new Object();

und sperren Sie dieses Objekt im Konstruktor.

lock(lockObj){}

Ich bin mir jedoch nicht sicher, ob es Situationen gibt, die aufgrund der Compileroptimierung in behandelt werden sollten .NET wie im Fall von Java

Der effizienteste Weg, dies zu tun, wäre die Verwendung der Interlocked-Inkrementierungsoperation.Der Zähler wird erhöht und der neu eingestellte Wert des statischen Zählers auf einmal (atomar) zurückgegeben.

class MyClass {

    static int _LastInstanceId = 0;
    private readonly int instanceId; 

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

In Ihrem ursprünglichen Beispiel wird die lock(this)-Anweisung nicht die gewünschte Wirkung haben, da jede einzelne Instanz eine andere „this“-Referenz hat und somit mehrere Instanzen gleichzeitig das statische Mitglied aktualisieren könnten.

In gewissem Sinne können Konstruktoren als Thread-sicher angesehen werden, da der Verweis auf das zu erstellende Objekt erst sichtbar ist, wenn der Konstruktor abgeschlossen ist. Dies trägt jedoch nicht zum Schutz einer statischen Variablen bei.

(Mike Schall hatte zuerst das verzahnte Gebiss)

Ich denke, wenn Sie das ändern Singleton-Muster eine Zählung einzubeziehen (natürlich unter Verwendung der Thread-sicheren Methode), ist das in Ordnung :)

Bearbeiten

Mist, den ich aus Versehen gelöscht habe!

Ich bin nicht sicher, ob es sich um Instanzkonstruktoren handelt SIND Thread-sicher, ich erinnere mich, dass ich darüber in einem Design-Pattern-Buch gelesen habe. Sie müssen allein aus diesem Grund sicherstellen, dass während des Instanziierungsprozesses Sperren vorhanden sind.

@rauben

Zu Ihrer Information: Diese Klasse ist möglicherweise kein Singleton. Ich benötige Zugriff auf verschiedene Instanzen.Sie müssen lediglich eine Zählung aufrechterhalten.Welchen Teil des Singleton-Musters würden Sie ändern, um eine „Zähler“-Inkrementierung durchzuführen?

Oder schlagen Sie vor, dass ich eine statische Methode zur Konstruktion verfügbar mache, die den Zugriff auf den Code blockiert, der den Zähler mit einer Sperre inkrementiert und liest?

public MyClass {

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

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

    private Int32 myCount;
    private MyClass() {
        myCount = counter;
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top