Domanda

Ho un file che viene letto e scritto. Devo assicurarmi che, quando è stato scritto, nessun altro proverà a scrivergli.

Metto un lucchetto su tutta la funzione che permette di leggere o scrivere ma ho ancora errori come Il processo non può accedere al file "FILENAME" perché è utilizzato da un altro processo.

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
}
È stato utile?

Soluzione

Stai creando un nuovo monitor da bloccare ogni volta che viene invocata la proprietà. Devi bloccare lo stesso monitor, altrimenti non ha alcun senso bloccare.

Dovresti anche usare un " lock " dichiarazione - non stai mai aspettando, quindi non ha senso pulsare. Al momento, se vengono generate eccezioni, finirai per "perdere". la serratura. Normalmente sarebbe un problema davvero grave, ma poiché non stai riutilizzando comunque il blocco, questo sta mascherando il problema.

Ad esempio:

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;
        }
    }
}

A parte questo, sembra che stia facendo più lavoro di quanto mi aspetterei in una proprietà. Sei sicuro che un metodo non avrebbe più senso?

Altri suggerimenti

Bene, Monitor.Enter blocca l'accesso di tutti i thread che tentano di posizionare un blocco sull'oggetto THE SAME. Ogni volta che entri nel tuo getter crei un nuovo oggetto, così ogni chiamante ottiene un nuovo lucchetto che non sa nulla l'uno dell'altro.

In altre parole, non esiste alcun blocco.

come nota a margine: perché non usi l'istruzione lock? Avrai comunque bisogno di un oggetto di blocco globale.

Il motivo della variabile globale rispetto alla variabile locale è che il BLOCCO sta effettivamente bloccando un punto di riferimento nella memoria come lo capisco. Ogni volta che crei un'istanza di un nuovo oggetto, ad esempio " Object obj = new object (); " ;, stai creando un nuovo oggetto, con il suo puntatore univoco in memoria. Quindi quando LOCK cerca di vedere se il punto in memoria è bloccato, non lo è. Perché è un nuovo punto di riferimento in memoria e l'unico che lo utilizza è il chiamante che entra nella tua proprietà. Avendo la tua variabile Obj dichiarata a livello globale, sarà sempre lo stesso punto in memoria e il blocco può effettivamente validare, che effettivamente quel punto in memoria è attualmente bloccato o può bloccarlo da solo.

Esempio: (grezzo ma penso che ottenga il punto)

Object obj = new object ();

Ora hai un punto in memoria che sembra un po 'come:

Memoria -

    * obj1

ora inserisci di nuovo la tua proprietà e crei ancora un nuovo oggetto. La tua memoria di sistema ora sembra un po '...

Memoria -

   * obj1
   * obj2

Al primo viaggio, il blocco sta controllando " Obj1 " in memoria. Poiché il chiamante del primo viaggio nella tua proprietà è l'unico che utilizza quell'istanza di Obj, è l'unico che lo bloccherebbe o controllerà mai. Perché sta guardando quella copia di quel riferimento Obj in memoria.

Nel secondo viaggio, il tuo lucchetto è segno di spunta " Obj2 " in memoria.

Quando si utilizza una variabile globale, quel punto in memoria persiste, quindi il blocco controlla sempre lo stesso punto in memoria. non si muove mai ed è sempre lo stesso punto di riferimento nella memoria. Quindi tutti i chiamanti della tua proprietà useranno sempre lo stesso punto di riferimento in memoria, il tuo blocco avrà successo come previsto.

Nota speciale: non sto dichiarando una durata di "obj". Sto semplicemente affermando come funziona in un processo multi-thread. spero che sia d'aiuto.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top