¿Cuál es la mejor manera de sincronizar el acceso XmlWriter a un archivo para evitar IOExceptions?

StackOverflow https://stackoverflow.com/questions/442235

Pregunta

Hay varios lugares en una aplicación que llaman a XmlWriter.Create en el mismo archivo, a todos se accede a través de la siguiente función. Cuando uno llama mientras otro todavía está escribiendo, recibo una IOException. ¿Cuál es la mejor manera de bloquear o sincronizar el acceso?

Aquí está la función que se está utilizando:

        public void SaveToDisk()
    {
        try
        {
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;
            using (XmlWriter writer = XmlWriter.Create(SaveFileAbsolutePath, settings))
            {
                XamlWriter.Save(this, writer);
                writer.Close();
            }

        }
        catch (Exception ex)
        {
            // Log the error
            System.Diagnostics.Debug.WriteLine(ex.Message);

            // Rethrow so we know about the error
            throw;
        }
    }

ACTUALIZACIÓN: Parece que el problema no es solo por las llamadas a esta función, sino porque otro hilo está leyendo el archivo mientras esta función está escribiendo. ¿Cuál es la mejor manera de bloquear para que no intentemos escribir en el archivo mientras se está leyendo?

¿Fue útil?

Solución

El uso de un bloqueo puede resolver su problema de concurrencia y, por lo tanto, evitar la IOException, pero debe recordar usar el mismo objeto en SaveToDisk y ReadFromDisk (supongo que esta es la función de lectura), de lo contrario, es totalmente inútil bloquear solo cuando leer.

private static readonly object syncLock = new object();

public void SaveToDisk()
{
     lock(syncLock)
     {
          ... write code ...
     }
}

public void ReadFromDisk()
{
     lock(syncLock)
     {
          ... read code ...
     }
}

Otros consejos

Un bloqueo estático debería hacer el trabajo de forma rápida y sencilla:

private static readonly object syncLock = new object();

entonces ...

public void SaveToDisk()
{
    lock(syncLock)
    {
        ...your code...
    }
}

También puede usar [MethodImpl (MethodImplOptions.Synchronized)] (en un método estático que acepta la instancia como argumento, por ejemplo, un método de extensión), pero un bloqueo explícito es más versátil.

Realmente usaría un ReaderWriterLock para maximizar la concurrencia Puede permitir múltiples lectores pero solo un escritor a la vez.

private ReaderWriterLock myLock = new ReaderWriterLock();

public void SaveToDisk()
{
     myLock.AcquireWriterLock();
     try
     {
          ... write code ...
     } 
     finally
     {
          myLock.ReleaseWriterLock();
     }
}

public void ReadFromDisk()
{
     myLock.AcquireReaderLock();
     try
     {
          ... read code ...
     } 
     finally
     {
          myLock.ReleaseReaderLock();
     }
}

Solo asegúrese de abrir el archivo con FileShare.Read para que las lecturas posteriores no fallen.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top