1

我有一个std::map<int, Object*> ObjectMap. 现在我需要更新地图,更新可以通过多个线程进行。因此,我们锁定地图以进行更新。但是每次更新都会导致冗长的计算,从而导致锁争用。

让我们考虑以下场景。

class Order  //Subject      
{ double _a, _b,_c;   
  std::vector<Customer* > _customers;  

  public:           
  void notify(int a, int b. int c)
  {    
     //update all customers via for loop. assume a for loop and iterator i    
     _customers[i] ->updateCustomer(a,b,c)
  }      

};
class SomeNetworkClass
{
private:
   std::map<int, Order*> _orders;
public:
   void updateOrder(int orderId, int a, int b, intc)
   {     
    //lock the map
      Order* order = _orders[orderId];
      order->notify();
    //release the lock
   }     
}

class Customer
{
public:
   void updateCustomer(int a,int b, int c)
   {
    //some lengthy function. just for this example. 
    //assume printing a, b and c multiple times
   }
}

每个客户也会更新,涉及一些计算。现在这是一个微不足道的观察者模式。但是,大量的观察者和每个观察者的巨大计算是这种设计的杀手锏。锁定争用在我的代码中上升。我认为这是一个实际问题,但人们使用更聪明的方法,我正在寻找那些更聪明的方法。我希望这次我有点清楚

谢谢希夫

4

1 回答 1

0

由于更新发生在地图的元素上,并且不将地图作为参数,我假设地图是不变的。

我将结构可视化为每个地图 ID 的对象链。现在,如果链包含不同的条目(并且 update 不会访问其链之外的任何元素或任何全局元素),您可以通过向每个链的根元素添加锁来摆脱困境。

但是,如果链中的对象可能被共享,那么您将遇到更困难的问题。在这种情况下,为每个对象添加一个锁就足够了。您可以证明,如果链表现正确(每个节点有一个子节点,但子节点可以共享),则必须以一致的顺序获取锁,这意味着不会出现死锁。

如果链之间有其他共享,那么遇到死锁的机会就很大。

假设您有案例 2,那么您的代码将大致如下所示

class Object
{
   Object * next;
   Lock l;
   Data d;
   void update(Data d_new)
   {
     l.lock();
     d = d_new;
     next->update(d_new);
     l.unlock();
   }
};
于 2012-02-29T03:31:22.987 回答