我有一个可以读写的文件。我需要确保在写入时,没有其他人会尝试写入它。
我对整个函数进行了锁定,允许读取或写入,但仍然会出现错误,例如 该进程无法访问文件'FILENAME',因为它正由另一个进程使用。
public static TYPE Property{
get{
data mydata;
Object obj = new object();
Monitor.Enter(obj);
// check if data has not changed
// if it has not, just read
using (Stream stream = File.Open(fileLocation, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {
//....
}
// else, if data changed, then need to write to file to save the new data
using (Stream stream = File.Open(fileLocation, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read)) {
BinaryFormatter bf = new BinaryFormatter();
try {
bf.Serialize(stream, (data);
}
//DONE processing
Monitor.Pulse(obj);
Monitor.Exit(obj);
return data
}
答案 0 :(得分:10)
您正在创建一个 new 监视器,以便在每次调用该属性时锁定。您需要锁定相同的监视器,否则根本没有锁定点。
你也应该只使用“锁定”声明 - 你永远不会等待,所以脉冲没有意义。目前,如果抛出任何异常,您最终会“泄漏”锁定。这通常是一个非常糟糕的问题,但是因为你还没有重新使用锁定,这就掩盖了这个问题。
例如:
private static readonly object monitor = new object();
public static TYPE Property
{
get
{
lock(monitor)
{
// check if data has not changed
// if it has not, just read
using (Stream stream = File.Open(fileLocation,
FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
....
}
// else, if data changed, then need to write to
// file to save the new data
using (Stream stream = File.Open
(fileLocation, FileMode.OpenOrCreate,
FileAccess.ReadWrite, FileShare.Read))
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(stream, data);
}
return data;
}
}
}
顺便说一下,这似乎比我在房产中所期望的更多。你确定一种方法没有意义吗?
答案 1 :(得分:4)
好吧,Monitor.Enter阻止任何试图锁定THE SAME对象的线程的访问权限。每次进入getter时都会创建一个新对象,因此每个调用者都会获得一个对彼此一无所知的新锁。
换句话说,没有锁定。
作为附注 - 为什么不使用lock语句?您仍然需要一个全局锁定对象。
答案 2 :(得分:1)
全局变量与局部变量的原因在于LOCK实际上是按照我的理解锁定了记忆中的参考点。每次实例化一个新对象,即“Object obj = new object();”时,您将创建一个新对象,并在内存中使用它自己的唯一指针。因此,当LOCK查看内存中的点是否被锁定时,它不是。因为它是内存中的全新引用点,并且唯一使用它的是调用者进入您的属性。将Obj变量全局声明后,它将永远是内存中的相同点,而lock实际上可以验证,实际上,内存中的那个点当前是锁定的,也可以自行锁定它。
示例:(粗略,但我认为它得到了重点)
Object obj = new object();
现在你的内存中有一点看起来有点像:
记忆 -
* obj1
现在您再次输入您的属性并再次创建一个新对象。你的系统内存现在看起来像......
记忆 -
* obj1
* obj2
在第一次旅行中,你的锁正在检查内存中的“Obj1”。由于第一次进入你的财产的来电者是唯一一个使用Obj实例的人,因此它是唯一一个锁定或检查锁定的人。因为它在内存中查看该Obj引用的副本。
在第二次旅行中,你的锁是内存中的“Obj2”。
当您使用全局变量时,内存中的该点仍然存在,因此锁定始终检查内存中的相同点。它永远不会移动,它总是在内存中的相同参考点。因此,您所有属性的所有调用者将始终在内存中使用相同的引用点,您的锁定将按预期成功。
特别提示:我没有说明“obj”的续航时间。我只是简单地说明这是多线程进程中的函数。希望有所帮助。