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

基于id字段的并发对象锁

  •  7
  • Toto  · 技术社区  · 15 年前

    我有一个生产者/消费者过程。使用的对象有一个ID属性(integer类型),我希望一次只使用一个具有相同ID的对象。我该怎么做?

    也许我可以这样做,但我不喜欢这样(创建的对象太多,而每天只能使用一个或两个ID相同的对象,并且锁(_-lockers)有点耗时:

        private readonly Dictionary<int,object> _lockers = new Dictionary<int,object>();
        private object GetLocker(int id)
        {
            lock(_lockers)
            {
                if(!_lockers.ContainsKey(id))
                    _lockers.Add(id,new object());
                return _lockers[id];
            }
        }
    
    
    
        private void Consume(T notif)
        {
                lock(GetLocker(notif.ID))
               {
                ...
               }
        }
    
    enter code here
    

    注意:同样的问题,id属性是string类型(在那个cas中,我可以锁定string.internal(currentObject.id)

    6 回复  |  直到 12 年前
        1
  •  12
  •   Damien_The_Unbeliever    15 年前

    如注释所示,一种方法是拥有一个固定的锁池(比如32),并使用ID模块32来确定要使用哪个锁。这将导致一些错误的锁共享。32是从空气中选择的数字-这取决于您的ID值分布、消费者数量等。

        2
  •  2
  •   Konamiman    15 年前

    你能让你的ID对每个对象都是唯一的吗?如果是这样,您可以对对象本身应用一个锁。

        3
  •  2
  •   Henk Holterman    15 年前

    首先,
    你有没有介绍过这一点? lock(_lockers) 确实是瓶颈吗?因为如果它没坏,就别修了。

    编辑:我没有仔细阅读,这是关于(大量)创建的助手对象。
    我认为达米恩对此有个好主意,我会留下一些关于弦乐的信息:

    关于

    注意:同一个问题和ID 属性的类型为string(在 cas也许我可以锁定 string.internal(当前对象.id)

    不,坏主意。你可以锁上一根绳子,但是你得担心它们会被关在什么地方。很难确定它们是独一无二的。

        4
  •  0
  •   weismat    15 年前

    我将把一个同步的FIFO队列看作是一个单独的类/单例,用于所有生成的对象——生产者将对象排队,消费者排队——因此实际的对象不再需要任何同步。然后在实际对象之外进行同步。

        5
  •  0
  •   Marek    15 年前

    如何从ID对象池分配ID并锁定这些对象?

    创建项目时:

    var item = CreateItem();
    ID id = IDPool.Instance.Get(id);
    //assign id to object
    item.ID = id;
    

    ID池创建和维护共享ID实例:

    class IDPool
    { 
        private Dictionary<int, ID> ids = new Dictionary<int, ID>();
        public ID Get(int id)
        {
        //get ID from the shared pool or create new instance in the pool.
        //always returns same ID instance for given integer
        }
    }
    

    然后锁定ID,该ID现在是consume方法中的引用:

    private void Consume(T notif)
    {
           lock(notif.ID)
           {
            ...
           }
    }
    

    这不是最佳解决方案,只会将问题转移到另一个地方——但是如果您认为您对锁有压力,那么使用这种方法可能会提高性能(例如,您的对象是在单个线程上创建的,那么您不需要同步ID池)。

        6
  •  0
  •   Kamran Khan    15 年前

    How to: Synchronize a Producer and a Consumer Thread (C# Programming Guide)

    除了简单的预防 与锁同时访问 关键字,进一步同步是 由两个事件对象提供。一个是 用于向工作线程发送信号 终止,另一个由 生产者线程向 当新项目具有 已添加到队列。这两个 事件对象封装在 类称为SyncEvents。这允许 要传递给对象的事件 代表消费者和 生产者线程容易。

    --编辑——

    simple code snippet 我有时会回信,看看这是否有帮助。我想这就是伟人所指的?

    --编辑——

    下面怎么样?

    1. 创建一个对象,比如ccustomer,它将保存:

      • 对象类型的对象
      • 还有一个bool,例如bool binprogress
    2. 可以保存的字典

    现在,当您检查以下内容时

    if(!_lockers.ContainsKey(id))
    _lockers.Add(id,new CCustomer(/**bInProgress=true**/)); 
    return _lockers[id]; **//here you can check the bInProgress value and respond accordingly**.