Pergunta

Eu tenho um arquivo que é lido e escrito. Eu preciso ter certeza de quando o seu foi escrito para, ninguém mais vai tentar escrever nele.

Eu coloquei um bloqueio em toda a função que permite a leitura ou escrita, quer, mas eu ainda obter erros como O processo não pode acessar o arquivo 'filename' porque ele está sendo usado por outro 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
}
Foi útil?

Solução

Você está criando um new monitor para bloqueio em cada vez que a propriedade é invocado. Você precisa bloquear no mesma Monitor de outra forma não há nenhum ponto em bloqueio em tudo.

Você também deve usar apenas uma declaração "bloqueio" - você nunca espera, então não há nenhum ponto em pulsante. Atualmente, se quaisquer exceções são lançadas, você vai acabar "vazamento" da fechadura. Que, normalmente, seria um problema muito ruim, mas como você não está reutilizando o bloqueio de qualquer maneira, que está mascarando o problema.

Por exemplo:

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

Como um aparte, isso parece que está fazendo mais trabalho do que eu realmente esperar em uma propriedade. Tens a certeza de um método não faria mais sentido?

Outras dicas

blocos

Bem, Monitor.Enter acessar de qualquer segmentos que tentam colocar um bloqueio no mesmo objeto. Toda vez que você digite o seu getter você cria um novo objeto, assim que cada chamador recebe um novo bloqueio que não sabe nada sobre o outro.

Em outras palavras, não há bloqueio.

Como uma nota lateral - por que você não use a instrução de bloqueio? Você ainda vai precisar de um objeto de bloqueio global.

A razão para a variável global contra a sua variável local é que o bloqueio seja realmente trancar um ponto de referência no memeory como eu o entendo. Toda vez que você instanciar um novo objeto, ou seja, "objeto obj = new Object ();", você está criando um novo objeto, com o seu próprio ponteiro único na memória. Então, quando olhares de bloqueio para ver se o ponto na memória está bloqueado, não é. Porque é uma marca novo ponto de referência na memória e o único a usar é o chamador entrar em sua propriedade. Com ter sua variável Obj declarou globalmente, será sempre o mesmo ponto na memória e bloqueio pode realmente validar, que na verdade, esse ponto na memória ou está atualmente bloqueado ou pode bloqueá-lo a si próprio.

Exemplo: (bruto, mas eu acho que ele começa o ponto)

Object obj = new object();

Agora você tem um ponto na memória que meio que parece com:

Memória -

    * obj1

Agora você entra em seu estabelecimento novamente e criar um novo objeto novamente. Memória do seu sistema agora parece um bocado como ...

Memória -

   * obj1
   * obj2

Na primeira viagem, o seu bloqueio está verificando "Obj1" na memória. Desde o chamador da 1ª viagem em sua propriedade é o único a usar essa instância de Obj, é o único que jamais iria bloquear ou verificá-lo para o bloqueio. Porque ele está olhando para essa cópia do que a referência Obj na memória.

Na segunda viagem, o bloqueio é checkign "Obj2" na memória.

Quando você usa uma variável global, desse ponto em persistir memória tão bloqueio verifica sempre o mesmo ponto na memória. que nunca se move e é sempre o mesmo ponto de referência na memória. Então, todos os chamadores de sua propriedade será sempre usando o mesmo ponto refernece na memória, o seu bloqueio vai ter sucesso como você espera que ele.

Especial Nota: Eu não estou afirmando um tempo de vida de "obj". Eu estou simplesmente dizendo como isso é functiong em um processo multi threaded. espero que ajude.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top