1

我有一个可以读写的文件。我需要确保它何时被写入,没有其他人会尝试写入它。

我锁定了允许读取或写入的整个函数,但我仍然遇到错误,例如进程无法访问文件“文件名”,因为它正在被另一个进程使用。

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
}
4

3 回答 3

10

您正在创建一个的监视器以在每次调用该属性时锁定。您需要锁定同一台显示器,否则根本没有锁定的意义。

您还应该只使用“锁定”语句 - 您永远不会等待,所以脉冲没有意义。目前,如果抛出任何异常,您最终将“泄漏”锁。这通常是一个非常糟糕的问题,但是由于您无论如何都没有重用锁,所以这掩盖了问题。

例如:

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;
        }
    }
}

顺便说一句,这看起来比我在房产中真正期望的要多。你确定一个方法不会更有意义吗?

于 2009-10-23T18:21:56.747 回答
4

好吧,Monitor.Enter 会阻止任何试图在同一对象上加锁的线程的访问。每次输入 getter 时,都会创建一个新对象,因此每个调用者都会获得一个新锁,而彼此之间一无所知。

换句话说,没有锁定。

作为旁注 - 为什么不使用 lock 语句?您仍然需要一个全局锁定对象。

于 2009-10-23T18:23:53.493 回答
1

全局变量与局部变量的原因是,据我所知,LOCK 实际上锁定了内存中的一个参考点。每次实例化一个新对象时,即“Object obj = new object();”,您正在创建一个新对象,它在内存中具有自己的唯一指针。所以当 LOCK 查看内存中的点是否被锁定时,它不是。因为它是内存中一个全新的引用点,唯一使用它的是进入您的属性的调用者。通过全局声明您的 Obj 变量,它将始终是内存中的同一点,并且 lock 实际上可以验证,实际上,内存中的该点当前已被锁定,或者它可以自行锁定它。

示例:(粗鲁,但我认为它得到了重点)

Object obj = new object();

现在你有一个记忆点,看起来有点像:

记忆 -

    * obj1

现在您再次输入您的属性并再次创建一个新对象。您的系统内存现在看起来像...

记忆 -

   * obj1
   * obj2

在第一次旅行中,您的锁正在检查内存中的“Obj1”。由于第一次进入您的财产的调用者是唯一使用该 Obj 实例的调用者,因此它是唯一会锁定或检查它是否锁定的调用者。因为它正在查看内存中那个 Obj 引用的副本。

在第二次旅行中,您的锁在内存中检查“Obj2”。

当您使用全局变量时,内存中的该点会持续存在,因此锁始终检查内存中的同一点。它从不移动,并且始终是内存中相同的引用点。因此,您的属性的所有调用者将始终使用内存中的相同参考点,您的锁定将如您所愿成功。

特别说明:我不是在说“obj”的生命周期。我只是在说明这是如何在多线程进程中运行的。希望有帮助。

于 2009-10-23T19:14:27.743 回答