线程的C#锁文件XML

线程的C#锁文件XML,c#,xml,multithreading,locking,C#,Xml,Multithreading,Locking,我对锁具持怀疑态度 我看到的所有示例中,lock station都是以相同的形式用于全局变量的,但在我的情况下,没有发生,那么我不知道如何避免错误“file用于另一个…” 我的案子。 用户转到form1,并在form1中向XML添加行。而在第二个平面中,线程获取该XML并将信息发送到服务器并更新该XML中的状态对象。 然后,当用户和线程同时写入时(一个由用户写入,另一个由第二个平面写入,xml保存抛出错误) 我正在这么做 form1 { var A = takeAllABCObjects()

我对锁具持怀疑态度

我看到的所有示例中,lock station都是以相同的形式用于全局变量的,但在我的情况下,没有发生,那么我不知道如何避免错误“file用于另一个…”

我的案子。 用户转到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();
 }
}
form1
{
var A=takeAllABCObjects();
var A=A+新对象();
保存对象(A);
}
应用程序所有时间生命周期中的第二个平面中的线程
{
var B=takeAllABCObjects();
B=更新对象SB();
保存对象(B);
}
类saveABCObjects(列出ABCObjects)
{
锁定(ABCObjects)
{
XmlSerializer serializer=新的XmlSerializer(typeof(List));
TextWriter TextWriter=newstreamWriter(“ABC.xml”);
序列化(textWriter,ABCObjects);
textWriter.Close();
}
}
那么我的问题是。。。 锁具的使用是错误的吗? 我应该如何使用它


Tnx和对不起,我的英文

如果您以写权限和“读”共享权限打开文件,您应该不会有问题

因此,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))
添加一点代码,但它应该允许一个进程在另一个进程读取时写入


至于没有读到结尾的读者,则完全是另一回事

我会使用
包装器
类来访问您的XML

因此,您的两个线程不知道彼此何时访问该文件,请让一个类自己执行该操作

我在想这样的事情:

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
,您可以使用
语句用
实例化它

它是最基本的表单,因此如果您使用它,您将无法访问两个不同的文件,只能跨线程打开一个文件

编辑:

用法示例:

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();
  }
}
类saveABCObjects(列出ABCObjects)
{
使用(var sync=newsynchronizedXMLAccess(…)
{
XmlSerializer serializer=新的XmlSerializer(typeof(List));
TextWriter TextWriter=新的StreamWriter(sync.Fs);
序列化(textWriter,ABCObjects);
textWriter.Close();
}
}

基本问题是线程和窗体使用的锁对象不同。我不知道你是如何创建线程的,但我已经编写了一个带有两个任务的小控制台应用程序,它将锁定并交替写入和读取文件。您必须向每个任务传递相同的锁对象,才能使其工作

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();
}
static void Main(字符串[]args)
{
var lockObject=新对象();
var fileName=@“C:\Users\kevin\Documents\test.txt”;
行动1=(o)=>
{
var i=0;
而(i++<1000)
{
//做一些不需要锁的事情
锁(o)
{
控制台。写入线(“线程1”);
//做一些需要锁的事情
var text=File.ReadAllText(文件名);
控制台写入线(文本);
writealText(文件名“\tThread1”);
}
}
};
//传入我们的共享锁对象
Task task1=新任务(action1,lockObject);
task1.Start();
行动2=(o)=>
{
var i=0;
而(i++<1000)
{
//做一些不需要锁的事情
锁(o)
{
//做一些需要锁的事情
控制台。写入线(“线程2”);
var text=File.ReadAllText(文件名);
控制台写入线(文本);
writealText(文件名“\tThread2”);
}
}
};
//传入我们的共享锁对象
Task task2=新任务(action2,lockObject);
task2.Start();
//休眠主线程,让2个线程完成它们的工作
睡眠(5000);
Console.ReadLine();
}

错误消息告诉您文件正在使用中。也就是说,它的文件句柄是打开的。这与c#
lock
语句无关,该语句只提供对关键代码部分的保护,但与打开的文件句柄无关。您可能应该使用信号量或互斥量而不是锁,并且如果目的是使用锁来防止对同一文件的多次写入(尽管这是个好主意),您可能每次都锁定在不同的列表上,因此它没有任何用处。@CharlesMager为保护并发文件访问,鉴于OP收到的错误消息,操作系统已经做得很好。尽管以非共享方式打开它会有所改进。旁注:不鼓励锁定公共对象(因此,在某种程度上,您的
lock
语句是错误的)。这与您看到的文件级锁定无关。“文件被另一个锁定…”是非常常见的问题,因此请确保搜索现有答案(其中99%的答案是“您没有在某处关闭文件”,这在您的情况下也可能是问题所在)。但进程B也会写入。首先“读取”所有对象,然后更新它们的状态,然后再“写入”并覆盖XML:/额外的一点是,如果线程要访问文件,它不会引发异常,而是让线程等待。在这种情况下,调用将是:SynchronizedXMLAccess.SynchronizedXMLAccess(…);saveABCObjects(列表);SynchronizedXMLAccess.Dispose();对吗?当两个线程都调用函数时,一个线程将等待另一个Dispose right?^ ^,tnx。当两个线程调用saveABCObjects()时,其中一个线程将在“使用”中等待,直到另一个线程结束,对吗?这就是全部想法:)您可能需要在