0

I had asked a question here: The process cannot access the file because it is being used by another process: Correct way to read\write to a file: heavily used application-Part II.

We have a heavily used .Net 3.5 application that reads "expensive to create" data and caches it. However we are getting a lot of errors around both reading the cache file and writing to the cache file. I have a single process, multiple threads and I want the application to synchronize access to a resource. I was advised to use a simple locking mechanism like lock or ReaderWriterLockSlim (see: http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim.aspx). This however seems to have made the problem much much worse in production.

EDIT After the change was implemented, a lot of the cache files have a ">" tag in the end. Due to this the files are no longer xml files.

Can someone look at the code and advise what could I be doing wrong?

Code before change:

private XmlDocument ReadFromFile()
{
    XmlDocument result=null;
    string fileSystemPath=FileSystemPath();
    try
    {
        result=new XmlDocument();
        using (StreamReader streamReader = new StreamReader(fileSystemPath))
        {
            result.Load(streamReader);
        }
    }
    catch (FileNotFoundException)
    {
        result=null;
    }
    return result;
}

private object thisObject= new object();
private void WriteToFile(string siteID, XmlDocument stuff)
{
    string fileSystemPath=FileSystemPath();
    lock(thisObject)
    {
        using (StreamWriter streamWriter = new StreamWriter(fileSystemPath))
        {
            stuff.Save(streamWriter);
        }
    }
}

Code after change:

private readonly ReaderWriterLockSlim readerWriterLockSlim = new ReaderWriterLockSlim();
private XmlDocument ReadFromFile()
{
    XmlDocument result = null;
    var fileSystemPath = FileSystemPath();          
    readerWriterLockSlim.EnterReadLock();
    try
    {
        result = new XmlDocument();
        using (var fileStream = new FileStream(fileSystemPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
        using (var streamReader = new StreamReader(fileStream))
        {
            result.Load(streamReader);
        }
    }
    catch (FileNotFoundException)
    {
        result = null;
    }
    finally
    {
        readerWriterLockSlim.ExitReadLock();
    }
    return result;
}


private void WriteToFile()
{
    var fileSystemPath = FileSystemPath();            
    readerWriterLockSlim.EnterWriteLock();
    try
    {
        using (var fileStream = new FileStream(fileSystemPath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite))
        using (var streamWriter = new StreamWriter(fileStream))
        {
            stuff.Save(streamWriter);
        }
    }
    finally
    {
        readerWriterLockSlim.ExitWriteLock();
    }
}
Community
  • 1
  • 1
Ajit Goel
  • 4,180
  • 7
  • 59
  • 107

1 Answers1

0

This code with some little changes should work

private readonly ReaderWriterLockSlim readerWriterLockSlim = new ReaderWriterLockSlim();
private XmlDocument ReadFromFile()
{
    XmlDocument result = null;
    var fileSystemPath = FileSystemPath();          
    readerWriterLockSlim.EnterReadLock();
    try
    {
        result = new XmlDocument();
        using (var streamReader = new StreamReader(fileStream))
        {
            result.Load(streamReader);
        }
    }
    catch (FileNotFoundException)
    {
        result = null;
    }
    finally
    {
        readerWriterLockSlim.ExitReadLock();
    }
    return result;
}


private void WriteToFile(XmlDocument stuff)
{
    var fileSystemPath = FileSystemPath();            
    readerWriterLockSlim.EnterWriteLock();
    try
    {
        using (var streamWriter = new StreamWriter(fileSystemPath))
        {
            stuff.Save(streamWriter);
        }
    }
    finally
    {
        readerWriterLockSlim.ExitWriteLock();
    }
}
Andriy Vandych
  • 144
  • 1
  • 6
  • And you must be convinced that stuff XmlDocument isn't changed from another thread while you are in WriteToFile method – Andriy Vandych Jul 23 '13 at 08:03
  • This also assumes that only a single file's access is being controlled. Or that it's okay to block reading files B, C, D, E and F while file A is being written. – Ross Presser Dec 16 '13 at 18:17
  • @RossPresser, current code will block all reads/writes to all files when writing, it guarantees the integrity of all files. If you want more productive code, you must use per file reader-writer lock. – Andriy Vandych Dec 24 '13 at 11:56