【问题标题】:C# concurrency, locking and dictionary objectsC# 并发、锁定和字典对象
【发布时间】:2009-01-13 21:52:48
【问题描述】:

我有一堆加载到数据库对象中的数据库实体。同一个 DB 实体可能被加载到多个 DB 对象中。数据库实体会定期需要特殊处理。该处理必须由一个线程一次执行。锁定在这里是有序的。

编辑:重要提示:该进程调用慢速 Web 服务。这就是我试图防止并发的原因。我不明白如何在没有锁的情况下安全地完成此操作。

所以我创建了一个“挂锁”对象,数据库对象将引用该对象进行锁定。挂锁对象是基于实体的,因此同一实体的两个或多个 DB 对象将使用相同的挂锁对象。我将这些挂锁存储在一个字典对象中,使用 DB 实体的 ID 作为键。挂锁对象也只是一个简单的字符串对象。这是正确的方法吗?我在想我要么过度工程化,要么简化了这个。如果方法是正确的,这段代码看起来如何?它可以工作,但我还没有在负载下对其进行测试。

谢谢:)

public static func(CustomObject o)
{
    if (ReadyForUpdate(o))
    {
        lock (LookupPadLockByID(object.ID)
        {
            if (ReadyForUpdate(o))
            {
                PerformUpdate(object);
            }
        }
    }
}

private static readonly object padlockLock = new object();
private static readonly Dictionary<int, string> padLocks = new Dictionary<int,string>();
private static object LookupPadLockByID(int uniqueID)
{
    lock (padlockLock)
    {
        if (!padLocks.ContainsKey(uniqueID))
        {
            padLocks.Add(uniqueID, uniqueID + " is locked");
        }
    }

    return padLocks[uniqueID];
}

【问题讨论】:

  • PeformUpdate 方法调用一个非常慢的 Web 服务,然后进行数据库更新。这是我防止并发所需要的。

标签: c# concurrency dictionary locking


【解决方案1】:

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

  • 您似乎没有从 padLocks 中移除锁 - 这是一个问题吗?
  • 你在padlockLock之外访问字典; return 应该在 lock

对于这一秒,这会更简单:

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

如果此代码是相当本地的(即您的对象尚未转义),您可能只是 lock 记录本身?简单多了……

【讨论】:

  • 我需要查看这个字符串实习。你不是唯一一个指出这一点的人。
【解决方案2】:

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

  1. 使用Dictionary&lt;int,object&gt; 作为padLocks 的类型,并将new object(); 作为值。
  2. 创建一个只保存id的类;如果您想在调试时查看 LockPad 类,这会更好地提高可读性。

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();
    }
}

然后,锁定那个类。

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

    • 这很有趣,但简单的答案是我不想阻止一个准备好更新的 CustomObject,如果它不依赖于另一个正在更新的 CustomObject。我想我正在寻找的是某种锁管理器。
    【解决方案4】:

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

    【讨论】:

    • PeformUpdate 方法的作用是调用Web 服务获取数据,然后将其与Web 服务数据一起保存到数据库中。我需要防止对 Web 服务的并发调用和对数据库的更新。
    • 当您知道您将对数据进行事务更新时,为什么还要使用 Web 服务来访问数据库?
    • Web 服务调用从第三方获取数据。该数据随后存储在数据库中。在数据从服务返回之前,我不会开始数据库事务。我不确定我是否按照您的要求进行操作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-09
    • 1970-01-01
    • 1970-01-01
    • 2021-11-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多