Reputation: 6848
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.
Upvotes: 3
Views: 4882
Reputation: 1313
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.
Upvotes: 2
Reputation: 8880
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 (e.g. 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
Upvotes: 1