2016-08-15 26 views
0

我不得不在我的代码中使用并发字典,其中“键”是对象,“值”是表示唯一由第三方库提供给所述对象的连接参数。存储连接参数,就像通过第三方库引发事件时一样,唯一键是事件参数之一,通过该参数我们可以找到正确的对象来处理进一步的代码。ConcurrentDictionary中条目的分层锁定策略以及C#中的字典本身

我有问题如下:

  • 偶尔并发字典需要与需要处理的对象的刷新列表进行更新。

  • 单个对象在处理过程中需要锁,因为抛出的事件必须按顺序执行而不是并行执行。 (这是我们所看到的是,工作有时是在不同的线程并行处理,却得到了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); 
    } 

所以现在的问题是,是否有申请锁定到就像一个主锁和等待所有儿童锁的对象字典内执行完刷新字典和继续之前外词典的方式处理传入的事件?

+0

你的代码很混乱。您正在使用'lockableKey'(设置为“key”,应该用双引号引起)从字典中检索自己(意思是:'key'只能使用“key”或“null”值,因为您正在使用'FirstOrDefault')。然后你试图通过值“key”(或'null',它会抛出一个异常)来锁定。不能保证第一个“键”等于字典中的“键”;它们都可以是相同价值的不同参考。您正在从字典中删除“密钥”,然后尝试解锁。为什么不调用:'TryRemove(theKey)'开头? –

+0

该示例不是实际实现的代码,而是更多的事件顺序的串行示例,正如我设想的那样(这将发生在不同的线程中)。这只是为了证明我面临的问题,我可能会遇到异常情况'对象同步方法是从一个未同步的代码块中调用的'。因此需要外锁和实际问题。 – sebpinski

+0

你有没有想过在单个线程中执行字典更新的可能性?就像使用'Task.Factory.StartNew'重载创建单线程调度程序并在此调度程序上创建更新任务一样? – galenus

回答

0

感谢大家的帮助,看起来以前的评论被删除了,帮助我找到了答案,所以我无法表明它应该到哪里去。

我执行了'ReaderWriterLockSlim' class。这允许多个读取器线程同时处理,但只有一个写入器线程。所以所有的处理线程都会取出读卡器锁,但更新字典的线程会取出写锁。写入器锁等待所有读卡器锁完成,但也优先于所有读卡器锁。所以一旦写入锁定被请求,阅读器锁定必须等到写入者完成后才能进入临界区。

除此之外,在读者线程中,我还将一个Monitor.TryLock应用于字典中的实际对象,以防止两个线程同时处理同一个项目。