Monitor.Pulse()无效

时间:2012-07-24 10:10:56

标签: c# multithreading monitor

这是我的代码片段。我想,一个线程应该工作而不必等到上一个线程完成。但我认识到所有线程都是按顺序启动的,我的脉冲调用对它们的工作方式没有影响。

class A
{
    string path = "file.xml";
    static public object _lock = new object();
    static private int accessCounter = 0;

    public List<T> GetItems()
    {
        List<T> result = null;
        lock (_lock)
        {

            while (accessCounter < 0)
                Monitor.Wait(_lock);
            accessCounter++;
            Thread.Sleep(1000);

            Monitor.Pulse(_lock);
            Thread.Sleep(1000);

            using (Stream stream = File.OpenRead(path))
            {
                XmlSerializer serializer = new XmlSerializer(typeof(List<T>), new Type[] { typeof(T) });
                result = (List<T>)serializer.Deserialize(stream);
            }
            accessCounter--;
            Monitor.Pulse(_lock);
        }
        return result;
    }
    public void AddItem(T item)
    {
      lock(_lock){if (accessCounter!=0) Monitor.Wait(_lock);
      accessCounter = -1;
      //some writing ooperations
      accessCounter = 0;
       }
    }
}

我知道如果条件在当前情况下无用,因为它总是 true 。更重要的是,他们应该同时工作,但不要。

编辑:此代码以下列方式从不同的线程调用:

.....
A a = new A();
var list = a.GetItems();
.....

它应该是某种写/读块。因此,如果线程想要读取而其他一些线程已经在读取文件,那么它就不必等待其他线程。现在,如果其他线程捕获了* _lock *

,则需要暂停所有读取线程

2 个答案:

答案 0 :(得分:1)

您的访问计数器检查错误。它应检查大于,不小于。

while (accessCounter > 0)
    Monitor.Wait(_lock);

但是,你的代码似乎有点奇怪。访问计数器检查发生在关键线程内部,锁定在_lock上,因此不应该有多于1个线程执行此代码。这就是您的代码不同时执行的原因。

另外,请注意Monitor.Wait 释放当前线程持有的锁 - 它不会等待锁变为空闲。

答案 1 :(得分:1)

框架已经提供了一个锁定机制(事实上,两个),它应该做你想要的(即允许许多同时读者,但写作是独家的(没有其他读者编写者同时) - ReaderWriterLock和ReaderWriterLockSlim。

您的代码可以修改为以下内容,以利用ReaderWriterLockSlim:

class A
{
    private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
    string path = "file.xml";
    static public object _lock = new object();
    static private int accessCounter = 0;

    public List<T> GetItems()
    {
        _lock.EnterReadLock();
        try
        {
            using (Stream stream = File.OpenRead(path))
            {
                var serializer = new XmlSerializer(typeof(List<T>), new[] { typeof(T) });
                return (List<T>)serializer.Deserialize(stream);
            }
        }
        finally
        {
            _lock.ExitReadLock();
        }
    }

    public void AddItem(T item)
    {
        _lock.EnterWriteLock();
        try
        {
            // Some writing operations
        }
        finally
        {
            _lock.ExitWriteLock();
        }
    }
}

值得注意的是,因为这种方法会泄漏内存,因为每次使用XmlSerializerXmlSerializer(Type)以外的构造函数创建新的XmlSerializer(Type, String)。这将导致每次都构建和加载新的XML序列化程序集,并且永远不会释放这些程序集。您需要切换到使用所提到的两个构造函数之一,或者缓存XmlSerializer实例(可能由typeof(T)键控),这样就不会泄漏内存。

有关详细信息,请参阅此处的“动态生成的程序集”部分:XmlSerializer documentation