类A和类B之间的线程同步:锁应该放在哪里

本文关键字:在哪里 同步 线程 和类 之间 | 更新日期: 2023-09-27 18:06:07

那么让我们假设我们有类A和类b。创建了类A的多个实例,每个实例在自己的线程上运行。让我们假设类B中有一堆资源,类a的所有实例都需要访问这些资源,但我希望一次只有一个线程操作这些资源。最明显的选择是lock语句。

我的问题是,锁应该在类B中(对于资源的getter和setter),或者如果它在类A中本身是相同的?(如下图所示)

class A
{
    B b;
    public A(B _b)
    {
        b = _b;
    }
    void DoStuff()
    {
        lock (this)
        {
            b.resource = "new values"
        }
    }

}
我希望你的问题很清楚。

类A和类B之间的线程同步:锁应该放在哪里

首先,不要锁定this。这只会导致死锁。
并且让A的每个实例锁在它们自己或它们自己的对象上是行不通的。

  1. 使用一个单独的对象,object lockObject = new object();锁定。
  2. lockObject应该在作用域和生命周期内尽可能接近受保护的资源。
  3. 设置lockObject为私有对象。

在您的例子中,第2点)指出lockobject应该是B的私有成员。

您仍然必须正确地编写B的所有方法。

假设你说:

but I want only one thread manipulating those resources at one time

那么,是的,他们需要在B类。目前的例子在A类中是足够公平的,但由于B是公共类,其他一些队友可能决定使用您的B类及其资源,如果您不提供锁定它的接口,那么您想要的报价将无法满足

如果您想从ONLY A访问B的资源(假设有一个类A的实例!,如果不是,那么你有一个问题,因为每个a对象使用自己的锁对象-这是无用的),我认为这是一个选择的问题。这两种情况都适用。但是,当您需要从其他类访问B的资源时,这是有意义的。例如,你有一个类C,它访问B的资源。那么,A类中的锁在这里不起作用。问题在于锁语句中使用的对象。用不同的方式思考,把对象放在B中,而不是放在a或其他类中。在类A中不使用语句锁(this),而是使用同步。对象,可以在锁语句中使用。例如:

void DoStuff()
{
    lock (b.LockObject)
    {
        b.resource = "new values"
    }
}

正如您所说,您还可以在资源getter/setter中使用lock语句。通过这种方式,您不需要记住在需要时锁定B对象,特别是在不同的类中使用(当然除了A)。我认为最后的选择是一个设计选择。如果你还需要非线程安全版本的资源getter/setter,使用上面的例子更有意义。