多线程锁和监视器类无法正常工作

时间:2009-10-23 18:18:26

标签: c# multithreading class locking monitor

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

我对整个函数进行了锁定,允许读取或写入,但仍然会出现错误,例如 该进程无法访问文件'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
}

3 个答案:

答案 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”的续航时间。我只是简单地说明这是多线程进程中的函数。希望有所帮助。