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