C#并发、锁定和字典对象

C#并发、锁定和字典对象,c#,concurrency,dictionary,locking,C#,Concurrency,Dictionary,Locking,我有一堆加载到DB对象中的DB实体。同一个DB实体可以加载到多个DB对象中。DB实体将定期需要特殊处理。此处理必须一次由一个线程执行。锁在这里是合适的 编辑:重要提示:该进程调用缓慢的web服务。这就是我试图阻止并发的原因。我不知道如何在没有锁的情况下安全地完成这项工作 因此,我创建了一个“挂锁”对象,它将被DB对象引用以进行锁定。挂锁对象基于实体,因此同一实体的两个或多个DB对象将使用同一挂锁对象。我使用DB实体的ID作为密钥将这些挂锁存储在dictionary对象中。挂锁对象也是一个简单的字

我有一堆加载到DB对象中的DB实体。同一个DB实体可以加载到多个DB对象中。DB实体将定期需要特殊处理。此处理必须一次由一个线程执行。锁在这里是合适的

编辑:重要提示:该进程调用缓慢的web服务。这就是我试图阻止并发的原因。我不知道如何在没有锁的情况下安全地完成这项工作

因此,我创建了一个“挂锁”对象,它将被DB对象引用以进行锁定。挂锁对象基于实体,因此同一实体的两个或多个DB对象将使用同一挂锁对象。我使用DB实体的ID作为密钥将这些挂锁存储在dictionary对象中。挂锁对象也是一个简单的字符串对象。这是正确的方法吗?我想我不是过度设计就是简化了。如果方法是正确的,那么代码看起来如何?它可以工作,但我还没有在负载下测试它

谢谢:)

公共静态函数(CustomObject o)
{
如果(准备更新(o))
{
锁(LookupPadLockByID(object.ID)
{
如果(准备更新(o))
{
执行更新(对象);
}
}
}
}
私有静态只读对象挂锁=新对象();
私有静态只读字典挂锁=新字典();
私有静态对象LookupPadLockByID(int uniqueID)
{
锁(挂锁)
{
如果(!padLocks.ContainsKey(uniqueID))
{
挂锁。添加(uniqueID,uniqueID+“已锁定”);
}
}
返回挂锁[唯一标识];
}

好吧,你最终锁定了一个字符串,这不是一个好主意(虽然串联意味着实习不应该是一个大问题)。更大的问题是:

  • 您似乎没有从
    挂锁上取下锁
    -这是个问题吗
  • 您在
    挂锁
    之外访问词典;
    返回
    应该在
对于第二种情况,这将更简单:

object itemLock;
if (!padLocks.TryGetValue(uniqueID, out itemLock)) {
    itemLock = new object();
    padLocks.Add(uniqueID, itemLock);
}
return itemLock;

如果此代码是相当局部的(即,您的对象尚未转义),您可以简单地
锁定
记录本身?简单得多…

我认为您设计过度了。如果您只需要保护您的DB实体(我假设在您的代码中由“object”表示,我将更改为“entity”),您可以将其用作锁。任何引用对象都可以用作锁:

public static func(CustomObject o)
{
    if (ReadyForUpdate(o))
    {
        lock (entity)
        {
                if (ReadyForUpdate(o))
                {
                        PerformUpdate(entity);
                }
        }
    }
}

如果您使用的是任何类型的标准数据库,我建议完全放弃这些客户端锁,转而使用事务锁和表/行锁。

锁定字符串不是一个好主意。我建议有两种选择:

  • 使用
    字典
    作为挂锁类型,并将
    新对象();
    作为值
  • 创建一个只保存id的类;如果您想在调试时查看您的LockPad类,这将有助于提高可读性
  • 密码锁等级:

    class LockPad {
        public int Id { get; private set; }
    
        public LockPad(int id) {
            this.Id = id;
        }
    
        public override string ToString() {
            return "lock of " + id.ToString();
        }
    }
    

    然后,锁定该类。

    PeformUpdate方法所做的是调用web服务来获取数据,然后将其与web服务数据一起保存到数据库中。我需要防止并发调用web服务和更新数据库。当您知道要进行事务性更新时,为什么要使用web服务访问数据库数据更新?web服务调用从第三方获取数据。该数据随后存储在DB中。在数据从服务返回之前,我不会开始DB事务。我不确定我是否遵循了您的要求。PeformUpdate方法调用一个非常慢的web服务,然后执行DB更新。这是我需要防止的并发性。这很有趣,但简单的回答是,如果一个CustomObject不依赖于另一个正在更新的CustomObject,我不想阻止它进行更新。我想我要找的是某种锁管理器。我需要研究这个字符串的内部处理。你不是唯一指出它的人。
    class LockPad {
        public int Id { get; private set; }
    
        public LockPad(int id) {
            this.Id = id;
        }
    
        public override string ToString() {
            return "lock of " + id.ToString();
        }
    }