Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the best way to synchronize XmlWriter access to a file to prevent IOExceptions?

There are multiple places in an application which call XmlWriter.Create on the same file, all accessed through the following function. When one calls while another is still writing, I get an IOException. What's the best way to lock or synchronize access?

Here's the function that's being used:

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

UPDATE: It looks like the problem isn't just from calls to this function, but because another thread is reading the file while this function is writing to is. What's the best way to lock so we don't try to write to the file while it's being read?

like image 292
Jon Galloway Avatar asked Mar 01 '23 02:03

Jon Galloway


2 Answers

Using a lock can solve your concurrency problem and thus avoid the IOException, but you must remember to use the same object either on SaveToDisk and ReadFromDisk (i assume this is the reading function), otherwise it's totally useless to lock only when you read.

private static readonly object syncLock = new object();

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

public void ReadFromDisk()
{
     lock(syncLock)
     {
          ... read code ...
     }
}
like image 146
Stefano Driussi Avatar answered Apr 27 '23 18:04

Stefano Driussi


A static lock should do the job quickly and simply:

private static readonly object syncLock = new object();

then...

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

You can also use [MethodImpl(MethodImplOptions.Synchronized)] (on a static method that accepts the instance as an argument - for example, an extension method), but an explicit lock is more versatile.

like image 20
Marc Gravell Avatar answered Apr 27 '23 19:04

Marc Gravell