abstract class Foo
{
private List<Object> container;
private bool update;
Foo Foo()
{
container = new List<object>();
update = false;
}
public abstract Bar CreateBar();
public void BeginUpdate()
{
if (!update)
{
Thread update_thread = new Thread(new ThreadStart(Update));
update_thread.Start();
}
}
private void Update()
{
update = true;
while (update)
{
lock (container)
{
if (...)
container.Add(this.CreateBar());
else
container.Remove(...);
}
Thread.Sleep(1337);
}
}
public void EndUpdate()
{
update = false;
}
public List<Object> Objects
{
get
{
lock (container)
{
return this.container;
}
}
}
}
当Foo之外的东西调用Foo的Object访问器时,
List<Objects> objects = foo_instance.Objects;
foreach (Object o in objects)
{
Thread.Sleep(31173);
}
锁定将如何发生?运行Update()的线程是否必须等到上面的foreach完成处理对象列表?我希望这两个可以同时工作,是制作对象深层副本的唯一解决方案吗?
答案 0 :(得分:3)
此代码有几个问题:
我会说在你开始担心要锁定什么以及何时锁定之前,你应该修复代码,这样它就不会有很多其他与线程相关的问题。
答案 1 :(得分:2)
您的代码没有按照您的想法执行。这个方法
public List<Object> Objects
{
get
{
lock (container)
{
return this.container;
}
}
}
在返回值后不保持锁定。所以你的循环没有被锁定。
您无法从clas
返回容器实例答案 2 :(得分:1)
您可以将锁定范围视为与功能范围类似。在访问器方法内部执行锁定只会在大括号之间锁定,一旦返回值,锁定将被释放。你需要在类之外(在调用者中)进行锁定才能获得所需的效果。
因此循环和线程都可以同时访问对象。这很糟糕,因为如果您的线程在循环期间更改了对象,则循环将抛出异常,因为集合已被修改。
答案 3 :(得分:0)
krosenvald是正确的,只要属性返回指向容器对象的指针,就会释放对象访问器上的锁...
在你的代码中
List<Objects> objects = foo_instance.Objects;
foreach (Object o in objects)
{
Thread.Sleep(31173);
}
锁定仅持续第一行...其中正在填充引用变量“objects”...实际上不需要为该行锁定任何内容,因为通过获取指针没有修改内存...