这是我的代码片段。我想,一个线程应该工作而不必等到上一个线程完成。但我认识到所有线程都是按顺序启动的,我的脉冲调用对它们的工作方式没有影响。
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 *
,则需要暂停所有读取线程答案 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();
}
}
}
值得注意的是,因为这种方法会泄漏内存,因为每次使用XmlSerializer
或XmlSerializer(Type)
以外的构造函数创建新的XmlSerializer(Type, String)
。这将导致每次都构建和加载新的XML序列化程序集,并且永远不会释放这些程序集。您需要切换到使用所提到的两个构造函数之一,或者缓存XmlSerializer
实例(可能由typeof(T)
键控),这样就不会泄漏内存。
有关详细信息,请参阅此处的“动态生成的程序集”部分:XmlSerializer documentation