处理来自数据库的队列时系统范围互斥锁的替代品?
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 后的某个时间点引发了异常。李>
【讨论】:
以上是关于处理来自数据库的队列时系统范围互斥锁的替代品?的主要内容,如果未能解决你的问题,请参考以下文章
《并发系列一》AbstractQueuedSynchronizer(AQS)- 互斥锁源码剖析
int pthread_mutex_init的获取互斥锁的范围