0

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

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

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

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

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

它应该是某种写/读块。因此,如果线程想要读取并且其他线程已经在读取文件,那么它不必等待其他线程。现在,如果其他线程捕获 *_lock*,则所有读取线程都需要挂起

4

2 回答 2

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

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

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

于 2012-07-24T12:10:47.720 回答
1

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

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

但是,您的代码似乎有点奇怪。访问计数器检查发生在一个关键线程内,锁定在 上_lock,因此无论如何都不可能有超过 1 个线程执行此代码。这就是您的代码没有同时执行的原因。

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

于 2012-07-24T10:15:33.673 回答