Question

J'ai un fichier qui est lu et écrit. Je dois m'assurer que, quand sa lettre sera écrite, personne d'autre n'essaiera de lui écrire.

Je mets un verrou sur toute la fonction qui permet de lire ou d’écrire mais j’obtiens toujours des erreurs telles que Le processus ne peut pas accéder au fichier 'FILENAME' car il est utilisé par un autre processus.

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
}
Était-ce utile?

La solution

Vous créez un nouveau moniteur à verrouiller chaque fois que la propriété est invoquée. Vous devez verrouiller le même moniteur, sinon le verrouillage ne sert à rien.

Vous devez également simplement utiliser un " verrouillage " déclaration - vous n'attendez jamais, il est donc inutile de pulser. Actuellement, si des exceptions sont générées, vous finirez par "fuir". le verrou. Ce serait normalement un très gros problème, mais comme vous ne réutilisez pas le verrou de toute façon, le problème est masqué.

Par exemple:

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

En passant, cela semble faire plus de travail que ce à quoi je m'attendais réellement dans une propriété. Êtes-vous sûr qu'une méthode n'aurait pas plus de sens?

Autres conseils

Eh bien, Monitor.Enter bloque l’accès de tous les threads essayant de verrouiller l’objet THE SAME. Chaque fois que vous entrez dans votre getter, vous créez un nouvel objet, ainsi chaque appelant reçoit un nouveau verrou qui ne sait rien l’un de l’autre.

En d'autres termes, il n'y a pas de verrouillage.

comme note latérale - pourquoi vous n'utilisez pas l'instruction de verrouillage? Vous aurez toujours besoin d'un objet de verrouillage global.

La raison de la variable globale par rapport à votre variable locale est que le verrou est en train de verrouiller un point de référence dans la mémoire tel que je le comprends. Chaque fois que vous instanciez un nouvel objet, c'est-à-dire "Objet obj = nouvel objet ();", vous créez un nouvel objet avec son propre pointeur unique en mémoire. Donc, quand LOCK cherche à voir si le point en mémoire est verrouillé, ce n'est pas le cas. Parce que c'est un tout nouveau point de référence en mémoire et que le seul à l'utiliser est l'appelant qui entre dans votre propriété. Lorsque votre variable Obj est déclarée globalement, il restera toujours le même point en mémoire et lock pourra en fait valider. En effet, ce point en mémoire est actuellement verrouillé ou peut le verrouiller lui-même.

Exemple: (brut mais je pense que ça donne raison)

Objet obj = nouvel objet ();

Vous avez maintenant un point en mémoire qui ressemble un peu à:

Mémoire -

    * obj1

Maintenant, vous entrez de nouveau dans votre propriété et créez à nouveau un nouvel objet. Votre mémoire système ressemble maintenant à ...

Mémoire -

   * obj1
   * obj2

Lors du premier voyage, votre cadenas vérifie "Obj1". en mémoire. Etant donné que l'appelant du premier voyage dans votre propriété est le seul à utiliser cette instance d'Obj, il est le seul à avoir jamais verrouillé ou vérifié le verrouillage. Parce qu'il regarde cette copie de la référence Obj en mémoire.

Lors du deuxième voyage, votre cadenas est coché "Obj2". en mémoire.

Lorsque vous utilisez une variable globale, ce point en mémoire persiste, donc lock vérifie toujours le même point en mémoire. il ne bouge jamais et c'est toujours le même point de référence en mémoire. Ainsi, tous les appelants de votre propriété utiliseront toujours le même point de référence en mémoire, votre verrou fonctionnera comme prévu.

Remarque spéciale: je ne déclare pas une durée de vie de "obj". Je dis simplement comment cela fonctionne dans un processus multi-threadé. espérons que cela aide.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top