C#锁定线程的XML文件

时间:2015-04-30 14:46:57

标签: c# xml multithreading locking

我对锁定声明有疑问

我看到的所有示例,锁定语句都以相同的形式用于全局变量,但在我的情况下没有发生,那么我不知道如何避免错误“文件被用于另一个......” / p>

我的情况。 用户转到form1,并在form1中添加行到XML。而在第二个平面中,一个线程获取该XML并将信息发送到服务器并更新此XML中的状态对象。 然后当用户和线程写在同一个(一个用户和另一个第二个平面,xml保存抛出错误) 我正在那样做

form1
{
  var A = takeAllABCObjects();
  var A = A + new objects();
  saveABCObjects(A);
}

Thread in second plane in all time life of app
{
  var B = takeAllABCObjects();
  B = UpdateObjectsB();
  saveABCObjects(B);
}


Class saveABCObjects(list<objects> ABCObjects)
{
 lock (ABCObjects)
 {
     XmlSerializer serializer = new XmlSerializer(typeof(List<objects>));
     TextWriter textWriter = new StreamWriter("ABC.xml");
     serializer.Serialize(textWriter, ABCObjects);
     textWriter.Close();
 }
}

然后我的问题是...... 锁定法使用是错误的? 我该怎么用呢?

Tnx并抱歉我的英文

3 个答案:

答案 0 :(得分:1)

基本问题是你的线程和表单没有使用相同的锁对象。我不知道你是如何创建你的线程但我已经写了一个小的控制台应用程序,其中包含2个将锁定并交替写入和读取文件的任务。您必须将相同的锁对象传递给每个任务才能使其正常工作。

static void Main(string[] args)
{
    var lockObject = new object();
    var fileName = @"C:\Users\kevin\Documents\test.txt";
    Action<object> action1 = (o) =>
    {
        var i = 0;
        while (i++ < 1000)
        {
            // do stuff that doesn't require the lock
            lock (o)
            {
                Console.WriteLine("In Thread1");
                // do stuff that does require the lock
                var text = File.ReadAllText(fileName);
                Console.WriteLine(text);
                File.WriteAllText(fileName, "\tThread1");
            }
        }
    };
    // Pass in our shared lock object
    Task task1 = new Task(action1, lockObject);
    task1.Start();
    Action<object> action2 = (o) =>
    {
        var i = 0;
        while (i++ < 1000)
        {
            // do stuff that doesn't require the lock
            lock (o)
            {
                // do stuff that does require the lock
                Console.WriteLine("In Thread2");
                var text = File.ReadAllText(fileName);
                Console.WriteLine(text);
                File.WriteAllText(fileName, "\tThread2");
            }
        }
    };
    // Pass in our shared lock object
    Task task2 = new Task(action2, lockObject);
    task2.Start();

    // sleep main thread and let the 2 threads do their stuff
    Thread.Sleep(5000);

    Console.ReadLine();
}

答案 1 :(得分:0)

如果您使用写入权限打开文件并且&#34;阅读&#34;分享权利你应该没事

所以processA打开写入

using(FileStream fs = File.Open("file.ext",FileMode.Open,FileAccess.Write,FileShare.Read))

和processB打开以供阅读

using(FileStream fs = File.Open("file.ext",FileMode.Open,FileAccess.Read,FileShare.ReadWrite))

添加了一些代码,但它应该允许一个进程写入而另一个进程正在读取

至于读者没有走完尽头是另一个故事

答案 2 :(得分:0)

我会使用wrapper类来访问您的XML

Sonce你的两个线程不知道彼此何时访问该文件让一个类自己做。

我在考虑这样的事情:

public class SynchronizedXMLAccess : IDisposable
{
    private static readonly Mutex _access = new Mutex();
    public FileStream Fs { get; private set; }

    public SynchronizedXMLAccess(String path, FileMode mode = FileMode.Open, FileAccess access = FileAccess.ReadWrite, FileShare sharing = FileShare.None)
    {
        _access.WaitOne();
        Fs = File.Open(path, mode, access, sharing);
    }


    #region Implementation of IDisposable
    public void Dispose()
    {
        Fs.Close();
        _access.ReleaseMutex();
    }

    #endregion
}

}

您需要实例化该类以访问文件,但它将确保它仅在线程之间打开一次。并且由于它实现了IDisposable,您将能够使用using语句对其进行实例化

这是最基本的形式,所以如果您使用它,您将无法访问2个不同的文件,只能在线程中打开一个文件

编辑:

用法示例:

Class saveABCObjects(list<objects> ABCObjects)
{
  using(var sync = new SynchronizedXMLAccess(...)) 
  {
    XmlSerializer serializer = new XmlSerializer(typeof(List<objects>));
    TextWriter textWriter = new StreamWriter(sync.Fs);
    serializer.Serialize(textWriter, ABCObjects);
    textWriter.Close();
  }
}