Frage

Ich habe eine Datei, die gelesen und geschrieben. Ich muss sicherstellen, wenn sein geschrieben worden ist, sonst niemand wird versuchen, es zu schreiben.

habe ich eine Sperre für die gesamte Funktion, die entweder lesen oder schreiben zu können, aber ich immer noch Fehler auftreten wie Der Prozess kann nicht die Datei ‚Dateinamen‘ zugreifen, da es von einem anderen Prozess verwendet wird.

public static TYPE Property{

get{
    data mydata;
    Object obj = new object();
    Monitor.Enter(obj);

    // check if data has not changed
    // if it has not, just read

    using (Stream stream = File.Open(fileLocation, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
        //....
    }
    // else, if data changed, then need to write to  file to save the new data

    using (Stream stream = File.Open(fileLocation, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read)) {
        BinaryFormatter bf = new BinaryFormatter();

        try {
            bf.Serialize(stream, (data);
        }
        //DONE processing

        Monitor.Pulse(obj);
        Monitor.Exit(obj);
        return data
}
War es hilfreich?

Lösung

Sie erstellen einen neuen Monitor jedes Mal sperren auf der Eigenschaft aufgerufen wird. Sie müssen sperren auf der gleichen überwachen sonst hat es keinen Sinn überhaupt in verriegelt wird.

Sie sollten auch einfach eine „Sperre“ Aussage - Sie nie warten, also gibt es keinen Punkt in Pulsen. Derzeit, wenn irgendwelche Ausnahmen geworfen werden, werden Sie am Ende „undicht“ die Sperre auf. Das wäre normalerweise ein wirklich schlechtes Problem sein, aber wie Sie nicht die Sperre ohnehin die Wiederverwendung, das ist maskiert das Problem.

Zum Beispiel:

private static readonly object monitor = new object();

public static TYPE Property
{
    get
    {
        lock(monitor)
        {
            // check if data has not changed
            // if it has not, just read
            using (Stream stream = File.Open(fileLocation, 
                   FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                ....
            }
            // else, if data changed, then need to write to 
            // file to save the new data
            using (Stream stream = File.Open
                       (fileLocation, FileMode.OpenOrCreate,
                        FileAccess.ReadWrite, FileShare.Read))
            {
                BinaryFormatter bf = new BinaryFormatter();
                bf.Serialize(stream, data);
            }
            return data;
        }
    }
}

Als beiseite, das sieht aus wie es ist mehr Arbeit zu tun, als ich wirklich in einem Hotel erwarten würde. Sind Sie sicher, ein Verfahren würde nicht mehr Sinn machen?

Andere Tipps

Nun, Monitor.Enter blockiert den Zugriff von allen Threads versuchen, auf dem gleichen Objekt eine Sperre zu setzen. Jedes Mal, wenn Sie geben Sie Ihre Getter Sie ein neues Objekt erstellen, so erhält jeder Anrufer eine neue Sperre, die nichts voneinander wissen.

Mit anderen Worten gibt es keine Verriegelung.

als Randnotiz - warum Sie nicht die lock-Anweisung verwenden? Sie werden nach wie vor ein globales Sperrobjekt benötigen.

Der Grund für die globale Variable im Vergleich zu Ihren lokalen Variablen ist, dass der LOCK tatsächlich einen Bezugspunkt in memeory nach unten blockiert, wie ich es verstehe. Jedes Mal, wenn ein neues Objekt instanziiert, das heißt „Object obj = new Object ();“, sind zu schaffen Sie ein neues Objekt, mit seinen eigenen einzigartigen Zeiger im Speicher. Also, wenn LOCK um zu sehen, sehen, wenn der Punkt im Speicher nach unten verriegelt ist, ist es nicht. Da es sich um eine brandneue referenzierten Punkt im Speicher ist und die einzige, mit ihm ist der Anrufer Eingabe Ihrer Immobilie. Mit nachdem global Ihren Obj Variable deklarierte, es wird immer die gleiche Stelle im Speicher und sperren kann tatsächlich bestätigen, dass in der Tat, wird dieser Punkt im Speicher entweder zur Zeit gesperrt oder es kann sie sich selbst sperren.

Beispiel: (roh, aber ich denke, es ist der Punkt wird)

Object obj = new object();

Jetzt haben Sie einen Punkt im Gedächtnis haben, die ein bisschen wie folgt aussieht:

Speicher -

    * obj1

Jetzt geben Sie Ihre Immobilie wieder und erstellen Sie noch einmal ein neues Objekt. Ihr Systemspeicher jetzt irgendwie sieht aus wie ...

Speicher -

   * obj1
   * obj2

Auf der ersten Reise, Ihre Sperre „Obj1“ im Speicher zu überprüfen. Da der Anrufer von der ersten Reise in Ihre Eigenschaft ist die einzige, die Instanz von Obj verwendet wird, ist es die einzige Person, die jemals sperren würde oder es überprüfen zu verriegeln. Da sieht es in dieser Kopie dieser Obj Referenz im Speicher.

Auf der zweite Reise, Ihr Schloss ist der prüfen „Obj2“ im Speicher.

Wenn Sie eine globale Variable verwenden, bleibt dieser Punkt im Speicher so sperren prüft immer den gleichen Punkt im Speicher. es bewegt sich nie und es ist immer der gleiche referenzierten Punkt im Speicher. Also alle Anrufer Ihrer Immobilie wird immer die gleiche refernece Punkt im Speicher verwenden, Ihre Sperre erfolgreich sein wird, wie Sie es erwarten.

Wichtiger Hinweis: Ich bin nicht eine Lebensdauer von „obj“ besagen. Ich stelle einfach, wie dies in einem Multi-Thread-Prozess functiong. hoffe das hilft.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top