c# - 如何根据 key 同步一段代码?

标签 c# .net wcf thread-safety

我有一个通过 WCF MSMQ 传输公开的服务。

此服务所做的部分工作是根据键(源,item_id)查找项目。 如果它找到一个,它会检索数据库标识符并使​​用它来更新记录。 如果找不到,则插入新记录。

我注意到有可能同时进入两个项目,都看到数据库中不存在一个项目,他们都尝试插入,但一个失败并出现约束错误。

我想限制对数据库查找的访问以及基于键(source,item_id)的后续代码,以便一次只有一个线程可以为该特定键完成工作。

我已经整理了一些代码来实现这一点,但我想就这是否有效或是否有更好的方法获得一些反馈。

使用 LockManager 类的代码:

public class ItemService
{
   private static LockManager lockManager = new LockManager();

   public void AddItem(Item item){
      var itemKey = item.Source + ":" + item.ItemId;
      lockManager.Work(itemKey, delegate(){ do stuff });
   }
}

LockManager 类:

public class LockManager
{

    private readonly IDictionary<string, LockObject> _lockTable = 
        new Dictionary<string, LockObject>();

    public void Work(string key, Action work)
    {
        var lockObject = BorrowLockObject(key);
        try
        {
            lock (lockObject)
            {
                work();
            }
        }
        finally
        {
            ReturnLockObject(lockObject);
        }
    }

    private LockObject BorrowLockObject(string key)
    {
        lock (_lockTable)
        {
            LockObject lockObject = null;
            if (_lockTable.ContainsKey(key))
            {
                lockObject = _lockTable[key];
            }
            else
            {
                lockObject = new LockObject(key);
                _lockTable[key] = lockObject;
            }
            lockObject.Open();
            return lockObject;
        }
    }

    private void ReturnLockObject(LockObject lockObject)
    {
        lock (_lockTable)
        {
            if (lockObject.Close())
            {
                _lockTable.Remove(lockObject.GetKey());
            }
        }
    }
}

LockObject 类:

public class LockObject
{
    private readonly string _key;
    private int _count;

    public LockObject(string key)
    {
        _key = key;
        _count = 0;
    }

    public string GetKey()
    {
        return _key;
    }
    public void Open()
    {
        lock(this)
        {
            _count++;    
        }    
    }

    /// <summary>
    /// Closes this lock object.
    /// </summary>
    /// <returns>True if this Lock Object is no longer in use.</returns>
    public bool Close()
    {
        lock(this)
        {
            _count--;
            return _count == 0;
        }
    }
}

最佳答案

Pair<Key,Action> 的同步集合和一个 WorkManager在一个单独的线程上作为一个队列(从后到前)工作会大大简化这个过程。您可以弹出并丢弃所有包含相同 key 的对,然后弹出一个对进行处理并完成对它的处理(执行此操作时锁定集合)。

>

  • 客户添加
    • 锁定收藏
    • 添加
    • 解锁收藏

>

  • 后台迭代:
    • 锁定收藏
    • 获取工作项(集合中的最后一项)
    • 从集合中删除
    • 解锁收藏
    • 工作...(与此同时客户添加更多,可能重复)
    • 锁定收藏
    • 删除所有具有相同 key 的项目(并妥善处理)
    • 解锁收藏

顺便说一句:public delegate void Worker();Action 中有一个快捷方式.

关于c# - 如何根据 key 同步一段代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6143279/

相关文章:

c# - 使用 "Start Debugging"和 "Start Without Debugging"启动应用程序时的不同堆栈跟踪

.net - System.Diagnostics.Process.Start() 从 WCF 服务运行时拒绝访问

c# - 如何合并这两个 linq 查询的输出?

c# - 如何使用 UniObjects for .net 保护 UniData session

c# - 如何限制DataGridView中可以选择的行数

c# - 如何停止 .net JSON 序列化引用以前的元素?

c# - Azure Functions 的 HostingEnviornment.QueueBackgroundWorkItem 等效项

c# - 多个用户的 WCF 身份验证自定义用户名和密码验证器

c# - 如何设置 ClientCredentials?

c# - 在 LINQ 中查找字符串 A 中字符串 B 的子字符串 C 的最有效方法