简体   繁体   中英

Handling concurrent reading/writing of a file

I have a web service that is generating random errors and I think I've found the fault.

Basically, it is reading a config file as follows, then loaded into an XmlDocument:

var config = File.ReadAllText(filename);
xmlDoc.Load(config);

However, at a later time (maybe a second later) one of the config values is updated and the file saved

xmlDoc.Save(filename);

So I'm now experiencing more errors (unfortunately the original developer added an empty try block so I can't check just now) during the first READ operation and I think it's because it's trying to read the file just as another process spawned from IIS is at the .Save part. I don't know how File.ReadAllText works and whether it will fail on a write locked file.

What's the best solution to handle this to ensure reading will always work? the value being written is just a counter and if it fails it is ignored as it's not that important but would prefer it was written. I guess I could put it into a separate config file and live with the error but I'd rather it was just one file.

Thanks.

You can use a lock to make sure that a read is completed before a write and vice verser. As in:

using System;
using System.Threading;

class Program
{
    static readonly object _fileAccess = new object();

    static void Write()
    {
        // Obtain lock and write
        lock (_fileAccess)
        {
            // Write data to filename
            xmlDoc.Save(filename);
        }
    }

    static void Read()
    {
        // Obtain lock and read
        lock (_fileAccess)
        {
            // Read some data from filename
            xmlDoc.load(filename);
        }
    }

    static void Main()
    {       
        ThreadStart writeT = new ThreadStart(Write);
        new Thread(writeT).Start();

        ThreadStart readT = new ThreadStart(Read);
        new Thread(readT).Start();
    }
}

With the lock, the Read() must wait for the Write() to complete and Write() must wait for Read() to complete.

To answer your question about how File.ReadAllText() works, looking at the source, it uses a StreamReader internally which in turn uses a FileStream opened with FileAccess.Read and FileShare.Read , so that would prevent any other process from writing to the file (eg your XmlDocument.Save() ) until the ReadAllText completed.

Meanwhile, your XmlDocument.Save() eventually uses FileStream opened with FileAccess.Write and FileShare.Read , so it would allow the File.ReadAllText() as long as the Save started before the ReadAllText .

References: https://referencesource.microsoft.com/#mscorlib/system/io/streamreader.cs,a820588d8233a829

https://referencesource.microsoft.com/#System.Xml/System/Xml/Dom/XmlDocument.cs,1db4dba15523d588

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM