处理来自数据库的队列时系统范围互斥锁的替代品?

Posted

技术标签:

【中文标题】处理来自数据库的队列时系统范围互斥锁的替代品?【英文标题】:alternatives to system-wide mutex when processing queue from DB? 【发布时间】:2012-05-04 20:58:23 【问题描述】:

我有一些(实体框架 4)代码如下所示:

class QueueItem
    public bool Processed  get; set; 
    // ... other fields


class QueueContext: System.Data.Entity.DbContext

    public System.Data.Entity.DbSet<QueueItem> Queue  get; set; 

    public void ProcessItems()
    
        do
        
            var item = Queue.FirstOrDefault(q => !q.Processed);
            if(item == null) break;
            ProcessItem(item);
            item.Processed = true;
            SaveChanges();
         while(true);
    

    //...

我想将其更改为 ProcessItems 方法外部的多线程。事实上,我希望多个进程/appDomains 同时运行此代码。如何防止多个进程从队列中选择相同的项目?我可以使用系统范围的(命名的)互斥体,但我看到那些非常慢。我正在寻找某种原子的“拉动并标记为进行中”。我使用 SqlServerCE4 作为数据存储。

【问题讨论】:

【参考方案1】:

使用真正的消息队列可能会更好,例如 MSMQ、Azure 队列,甚至是 Sql Server Service Broker(当然不适用于 CE)。像 Redis 这样的东西可能也更容易。如果这些都不是一个选项,您可能必须执行以下操作:

    将“InProgress”字段添加到您的表中 确保为表启用乐观并发(例如通过 RowVersion) 查询时,查询既不是 InProgress 也不是 Complete 的内容 当您获得第一个实体时,更新 InProgress 字段以表明您已抓取它,然后保存更改。 如果发生并发异常,请处理它。这意味着其他人已经在您同时抢到了这个项目,但他们先保存了。在这种情况下,请重新启动循环并寻找下一个循环。 如果未引发异常,则照常处理,但必须使用适当的错误处理以确保始终清除 InProgress,即使在将异常标记为 InProgress 后的某个时间点引发了异常。李>

【讨论】:

以上是关于处理来自数据库的队列时系统范围互斥锁的替代品?的主要内容,如果未能解决你的问题,请参考以下文章

TencentOS tiny深度源码分析—— 互斥锁

2019年8月15日星期四(系统编程)

《并发系列一》AbstractQueuedSynchronizer(AQS)- 互斥锁源码剖析

int pthread_mutex_init的获取互斥锁的范围

C#多线程 一个缓冲队列,一个生产者线程,一个消费者线程,这两个线程同时操作这个队列,必须加互斥锁吗

在 C# 中使用全局互斥锁的好模式是啥?