我正在尝试锁定一个对象,同时遍历它的元素。我的数组列表allThreads实际上没有被锁定,因为在执行"foreach“的过程中,我得到了一个异常,说”集合已被修改;枚举操作可能无法执行“。我以为这就是锁的全部问题?
lock (mApp.allThreads)
{
foreach (Thread t in mApp.allThreads)
if (t.Name == "OpcDAWriter" && t != Thread.CurrentThread)
t.Join();
}发布于 2010-11-29 20:33:17
我想你可能误解了lock为你做了什么。它不会阻止其他代码操作您锁定的对象。它所做的是防止一个线程在一个对象上获取long,而另一个线程持有锁。
如果您希望防止一个线程在另一个线程对集合进行迭代时操作该集合,则需要将迭代代码和操作代码都放在lock块中,锁定同一对象。
简单示例:
class LockDemo
{
private IList<string> _items;
private object _lock = new object();
public LockDemo()
{
_items = new List<string>(new[] { "one", "two", "three" });
}
public void RemoveItem(string item)
{
lock (_lock)
{
_items.Remove(item);
}
}
public void DoSomethingThatIteratesOverTheList()
{
lock (_lock)
{
foreach (var item in _items)
{
// do something with item
}
}
}
}请注意,对列表的所有访问(本例中的构造函数除外)都包装在锁定同一对象的lock块中。还要注意,这个对象不是列表本身,而是一个仅用于锁定目的的对象。这表明lock本身并不锁定对象,但提供了一种机制来控制代码的哪些部分可以由不同的线程并行执行,哪些不可以。
发布于 2010-11-29 20:28:13
您正在联接到t线程中,因此它可能会从mApp.allThreads中删除,或者由于联接而发生其他事情,从而修改集合。
此外,仅仅因为您正在查看对象,并不是所有其他方法都可以锁定它,只有当所有访问该对象的方法都锁定它时,该锁才有效。您可以尝试使用外部对象作为锁定参数,例如:
private readonly _lock = new object();
[...]
lock(_lock)
{
foreach....
}但我怀疑这不会改变任何事情。
https://stackoverflow.com/questions/4303623
复制相似问题