【问题标题】:Wants to apply ID based lock in C# [duplicate]想在 C# 中应用基于 ID 的锁 [重复]
【发布时间】:2020-04-14 11:17:10
【问题描述】:

我正在编写一个如下的 c# 类。我有学生的卷号作为表中的唯一键是否有任何方法可以根据 rollNo 锁定,如果不允许从具有相同卷号的多个线程进行修改并且应该允许使用不同的卷号。

Class ABC 
{
    public Void UpdateStudent(int rollNo)
    {
        student = fetchRecord();

        if(some condtion)
        {
            //Update Student table
        }

        if(some condtion)
        {
            //Update Student table
        }

        if(some condtion)
        {
            //Update Student table
        }

        // enter code here
    }
}

【问题讨论】:

  • rollNo 的取值范围是多少?
  • 大于0到10,000
  • 你当然可以,但一般来说,无论如何数据库就是为了这个。
  • 但问题是我正在缓存读写,有时一个学生读取和另一个相同卷号的学生更新这会产生问题,缓存新数据需要几秒钟
  • 你能展示缓存读写的代码吗?您将缓存数据存储在哪里?

标签: c# .net multithreading


【解决方案1】:

我会用Dictionary 的锁来做到这一点。因此,对于每个卷号,您都有一个锁对象,然后您可以使用它一次仅在一个线程上安全地更新表。

Class ABC 
{
    private Dictionary<int, object> locks = new Dictionary<int, object>();
    private object locks_lock = new object();

    private object GetLock(int rollNo)
    {
        object lock;
        lock(locks_lock) {
            // get the lock for the provided rollNo
            if(!locks.TryGetValue(rollNo, out lock)) {
                // the lock for this rollNo doesn't exist yet, create it now
                lock = new object();
                locks.Add(rollNo, lock);
            }
        }
        return lock;
    }

    public void UpdateStudent(int rollNo)
    {
        var student = fetchRecord();

        if(some condition) {
            lock(GetLock(rollNo)) {
                //Update Student table
            }
        }
        if(some condition) {
            lock(GetLock(rollNo)) {
                //Update Student table
            }
        }

        // enter code here ...

    }
}

【讨论】:

  • 这有几个问题:(a) 您还需要锁定对字典的访问权限(当您Add“锁定”时)。 (b) 通过在 rollNo 和 lock 之间建立一对一的关系,只要外部类的实例存在,您就会为学生(或 rollNo)保留一个条目。将 rollNo 分组到存储桶中,并为每个存储桶设置一个锁。这将立即锁定“一群学生”,是的,但您不必在字典中保留无限数量的条目(也许,永远)。
  • 我修复了 (a) 问题。关于(b)问题:我认为这不是记忆方面的问题,也不是实施方面的问题。从 Dictionary 中检索一个值非常快,接近 O(1)。
  • 也许,但还有其他解决方案一开始就没有那个“问题”。当然是 YMMV。
  • 这将在“学生表”是一个线程安全容器的假设下工作,因此它可以被多个线程并行地改变。恕我直言,这不太可能。
【解决方案2】:

您可以使用ConcurrentDictionary 持有锁。

public class ABC
{
    static readonly ConcurrentDictionary<int, Lazy<object>> Locks = new ConcurrentDictionary<int, Lazy<object>>();

    public void UpdateStudent(int rollNo)
    {

        lock (Locks.GetOrAdd(rollNo, _ => new Lazy<object>()))
        {
            // do work here
            Console.WriteLine("Updating student");
            Thread.Sleep(1000);
            Locks.TryRemove(rollNo, out _);
        }
        Console.WriteLine("Student updated");
    }
}

【讨论】:

  • 注意:GetOrAdd 不是线程安全的:andrewlock.net/…
  • 谢谢。我很确定我测试过它,但不记得如何了。我已按照链接中的建议应用了Lazy 技巧
猜你喜欢
  • 1970-01-01
  • 2015-10-14
  • 1970-01-01
  • 2020-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多