代码之家  ›  专栏  ›  技术社区  ›  DigitalZebra

关于锁对象和子类的问题

  •  2
  • DigitalZebra  · 技术社区  · 16 年前

    我有一个基类,它有一个私有锁定对象,如下所示:

    class A
    {
        private object mLock = new object();
    
        public virtual void myMethod()
        {
            lock(mLock)
            {
                // CS
            }
        }
    }
    

    此锁定对象用于大多数 A

    现在,假设我继承了 A 像这样:

    class B : public A
    {
        public override void myMethod()
        {
            lock(???)
            {
                // CS of mymethod here
    
                // Call base (thread safe alread)
                base.myMethod();
            }
        }
    }
    

    B 线程安全?应该 B A 做?如果我需要像上面那样调用基方法呢?

    编辑: 有人问我说的“线程安全”是什么意思。。。我要澄清的是,我正在试图通过互斥实现线程安全。。。一次只能有一个线程执行可能改变对象状态的代码。

    5 回复  |  直到 16 年前
        1
  •  4
  •   Jon Skeet    16 年前

    protected object SyncLock { get { return mLock; } }
    

    如果B有自己的锁对象,那么很容易得到:

    • 使用不同的锁,可能导致竞争条件(它 可以 很好-如果在按住锁B时发生的操作与在按住锁A时发生的操作正交,则您可以侥幸逃脱。)

    base.myMethod 递归地获取/释放锁。

    说了这么多,我很想 非线程安全或不可变的类(只有关于线程的类需要线程知识)和

        2
  •  4
  •   Grzenio    16 年前

    这要看情况了。如果您的子类只使用基类中的安全方法,并且没有添加任何额外的不安全状态,那么您就不必做任何事情(首选)。如果它添加了一些与基类的状态不相关的额外状态,那么您可以在子类中创建一个单独的锁对象并使用它。另一方面,如果您需要确保新状态和基类中的状态以某种“事务性”方式更改,那么我将保护基类中的lock对象并使用它。

        3
  •  4
  •   Adam Robinson    16 年前

    只是使用 lock

    你所做的一切 A 使得一次不能有多个线程调用包含在 lock(mLock) . 线程安全是一个宽泛的术语,防止并发调用只是一个方面(并不总是您想要或需要的)。如果这是你需要的,那么你显然采取了正确的方法。一定要确定。

    1. B protected (或 internal 如果它和 A A 锁定(mLock) 阻碍
    2. B 包含在 锁定(mLock) 阻止并不提供任何需要防止并发调用的操作
    3. 只调用函数 包含在 块,还提供了自己的操作,要求您防止并发调用。

    可以归结为两个不相关的问题:

    1. 威尔 B 与…互动 以一种需要保护的方式(换句话说,以一种 还没有 受保护的)?
    2. B 公开需要保护的功能,如果是,它们是否应该使用相同的锁定对象?

    如果1)为true,2)为true,并且它们应该使用相同的锁定对象,则需要通过 受保护的 属性并在所有锁中使用它(我建议在 A 以及可读性)。

    如果两者都不是真的,那就别担心了。如果2)为true,但它们不需要使用相同的锁定对象(换句话说,可以接受对 A B ),则不必担心暴露锁定对象。记住,任何电话 在上生成函数 已经受到了法律的保护 锁定(mLock)

        4
  •  2
  •   Andy Mortimer    16 年前

    因此,当您像这样锁定整个对象时,必须小心锁内运行的代码:“坏”代码在锁内运行会影响代码的正确性。

    由于子类化引入了原始对象无法控制的代码,因此使用这样的自锁类通常被视为一种危险的方法,因此一种流行的约定是“不要这样做”

    如果考虑到可能出现的问题,您仍然希望采用这种方法,那么使可锁定对象受保护而不是私有将允许您在同一基类锁中包含子类操作。

        5
  •  -3
  •   Mashmagar    16 年前

    lock(this) ,而不是仅为锁定而创建另一个对象的实例。这两种情况都应该适用。