【发布时间】:2016-08-19 17:03:43
【问题描述】:
我不得不在我的代码中使用并发字典,其中“键”是一个对象,“值”是一个 int,表示第三方库提供的与所述对象的唯一连接参数。存储连接参数,因为当通过第三方库引发事件时,唯一键是事件参数之一,我们可以使用它找到正确的对象来处理进一步的代码。
我遇到的问题如下:
有时,并发字典需要使用刷新的需要处理的对象列表进行更新。
各个对象在处理过程中需要锁定,因为抛出的事件必须按顺序执行,而不是并行执行。 (这已成为最近的要求,因为我们看到任务有时在不同线程上并行处理,并在保存到数据库时得到 OptimisticConcurrencyException。)
对字典中的单个对象应用锁定不是问题,但是当我尝试从字典中删除当前锁定的对象同时刷新列表时会出现新问题。
我尝试编写一个小型控制台应用程序,它可以按顺序执行有问题的步骤,即“Monitor.Exit(key);”行抛出异常“对象同步方法是从未同步的代码块中调用的。”
class Program
{
static ConcurrentDictionary<object, int> _handles = new ConcurrentDictionary<object, int>();
static void Main(string[] args)
{
object lockableKey = 'key';
_handles.AddOrUpdate(lockableKey, 10, (oldkey, oldvalue) => 10);
var key = _handles.Keys.FirstOrDefault(h => h == lockableKey);
Console.WriteLine("key found, beginning to lock");
Monitor.Enter(key);
Console.WriteLine("key locked");
////Console.WriteLine("applying outer lock, hoping for code to stop executing");
////Monitor.Enter(_handles);
Console.WriteLine("Removing key from dictionary");
int dummy;
_handles.TryRemove(lockableKey, out dummy);
Console.WriteLine("Removing lock from object removed from dictionary");
Monitor.Exit(key);
}
所以问题是,有没有一种方法可以将锁应用于外部字典,其作用类似于主锁,并等待字典内对象上的所有子锁完成执行,然后再刷新字典并继续处理传入的活动?
【问题讨论】:
-
您的代码令人困惑。您正在使用
lockableKey(设置为“key”,应该用双引号编写)从字典中检索自己(意思是:key只能具有值“key”或null,因为您正在使用FirstOrDefault)。然后您尝试通过值“key”(或null,这将引发异常)锁定。不能保证第一个“key”等于字典中的“key”;它们都可以是相同值的不同引用。您正在从字典中删除“密钥”,然后尝试解锁。为什么不先打电话:TryRemove(theKey)? -
该示例不是实际实现的代码,而是我设想的事件顺序的序列示例(这将发生在不同的线程中)。这只是为了证明我面临的问题,即我可能会遇到异常“对象同步方法是从不同步的代码块中调用的”。因此需要外锁和实际问题。
-
您是否考虑过在单个线程中执行字典更新的可能性?比如制作单线程调度器并在这个调度器上使用
Task.Factory.StartNew重载创建更新任务?
标签: c# multithreading