锁定如何在.net中表现?

时间:2008-11-28 17:50:20

标签: c# .net multithreading locking

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完成处理对象列表?我希望这两个可以同时工作,是制作对象深层副本的唯一解决方案吗?

4 个答案:

答案 0 :(得分:3)

此代码有几个问题:

  1. 您没有启动帖子
  2. 你可以有多个线程调用BeginUpdate的竞争条件(可能不适用于你的程序),两者都看到更新是假的,并且都启动一个线程,现在你有两个线程在运行,可能互相干扰,因为你有一个包含共享数据的字段成员
  3. 锁定房产有什么意义?你不需要它。请注意,由于内部更新,您从属性返回的容器有时会处于不稳定状态。这意味着调用该属性的外部代码必须在访问其内容之前锁定容器本身。您不需要锁来返回容器引用。
  4. 竞争条件如果您调用EndUpdate然后在彼此之后调用BeginUpdate,旧线程可能没有机会退出
  5. 我会说在你开始担心要锁定什么以及何时锁定之前,你应该修复代码,这样它就不会有很多其他与线程相关的问题。

答案 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”...实际上不需要为该行锁定任何内容,因为通过获取指针没有修改内存...