Question

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?

Was it helpful?

Solution

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

OTHER TIPS

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.

I'd actually use a ReaderWriterLock to maximise concurrency. You can allow multiple readers but only one writer at a time.

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

Just make sure to open the file with FileShare.Read so that subsequent reads don't fail.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top