简体   繁体   English

处理文件的并发读/写

[英]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. 我有一个产生随机错误的Web服务,我想我已经找到了错误。

Basically, it is reading a config file as follows, then loaded into an XmlDocument: 基本上,它是按如下方式读取配置文件,然后加载到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. 所以我现在遇到了更多错误(不幸的是原始开发人员添加了一个空的try块,所以我现在无法检查)在第一次READ操作期间我认为这是因为它试图读取文件就像从IIS生成的另一个进程一样在.Save部分。 I don't know how File.ReadAllText works and whether it will fail on a write locked file. 我不知道File.ReadAllText如何工作以及它是否会在写锁定文件上失败。

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. 使用锁定,Read()必须等待Write()完成,Write()必须等待Read()完成。

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. 要回答有关File.ReadAllText()如何工作的问题,查看源,它在内部使用StreamReader ,后者又使用FileStream打开的FileAccess.ReadFileShare.Read ,这样就可以防止任何其他进程写入文件(例如你的XmlDocument.Save() )直到ReadAllText完成。

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 . 同时,您的XmlDocument.Save()最终使用FileStream打开FileAccess.WriteFileShare.Read ,因此只要在ReadAllText之前启动Save ,它就会允许File.ReadAllText()

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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