【问题标题】:Possible to lock a {portion} of an array in C#? or have dynamic lock array?可以在 C# 中锁定数组的 {portion} 吗?还是有动态锁数组?
【发布时间】:2011-10-10 22:07:26
【问题描述】:

我有一个我正在跟踪的对象的动态列表,并且将来可能会使用许多线程。有人可以看看这个实现是否有错误吗?

换句话说,我想跟踪这个对象的许多实例:

object AzureBatchTrackerLock = new object();
Dictionary<string, List<TableServiceEntity>> AzureBatchTracker = new Dictionary<string, List<TableServiceEntity>>();

我目前的方法是使用 lock 和专用对象,以及 List 和 Dictionry 来处理动态数组...

BatchThread.cs

/// This object itself contains a dictionary AND a lock.  
///  This object will ALSO be contained in a second dictionary that also has its own lock 
public class BatchThread
{ 
   // When I perform updates to AzureBatchTracker dictionary, lock the following
  internal readonly object AzureBatchTrackerLock = new object();
  internal Dictionary<string, List<TableServiceEntity>> AzureBatchTracker = new Dictionary<string, List<TableServiceEntity>>();
} 

BatchProcessor.cs

public class BatchProcessor
{ 
 // Class-wide scope
 readonly object _BatchEntriesLock = new object();
 Dictionary<string, BatchThread> _BatchEntries = new Dictionary<string, BatchThread>();

 // The "outer loop"
 public BatchThread GetAnEntry(string ThingToProcess)
 { 
     // Prepare return variable
    BatchThread foundBatchThread = null;

    // And then I would select an object like this:
    // Notice that I'm performing what may be a concurrent entry here
    // on a non-locked object ............................
    //  Is this a bad idea?  Should I lock?  Does it matter?
    //  If I must lock, want to exit as quickly as possible. Must not be later than the next lock() command
    var activeRow = _BatchEntries[ThingToProcess];


    // Since I have the object I care about, I'll work with the "secondary" lock object 
    // It works in practice, but I don't know what kind concurrency issues I'll run into.
    lock (activeRow.Value.AzureBatchTrackerLock)
    {
       // Add and remove from the collection 
       ActiveRow.Value.AzureBatchTracker.Add(new exampleEntry); 

       // Do Stuff

       ActiveRow.Value.AzureBatchTracker.Remove(something);

         foundBatchThread =  activeRow.Value.AzureBatchTracker[ThingToProcess];
     }

     return foundBatchThread;
   }

   // The inner loop
   // Called whenever the "Outer" array needs to be expanded
   public void AddNewBatchEntry(string newEntryName)
   {  
     lock (_BatchEntriesLock)
      {
         // Add placeholder to the collection
         _BatchEntries.Add( newEntryName, new BatchThread() ); 

          // Do Stuff

       }
   }
  }  

您在此实现中发现任何缺陷吗?有没有更好的办法?

【问题讨论】:

    标签: c# multithreading concurrency dictionary locking


    【解决方案1】:

    如果您使用的是 .NET 4.0,则可以使用 ConcurrentDictionary

    【讨论】:

    • 同意,无需重新发明轮子。
    • 感谢您的提示,我不知道新课程的存在!
    【解决方案2】:

    是的,您需要锁定 var ActiveRow = BatchEntries[ThingToProcess];,因为您还要添加到字典中(除非您确定它们发生在不同的时间)。如果您可以保证在“外部循环”执行时不会添加,那么不,您不需要锁定 - 您可以进行并发读取。

    如果 add 方法很少发生,读取很多,你应该查看ReaderWriterLock

    【讨论】:

    • 我很快就会阅读该课程。我想 MSDN 会告诉我为什么它优于 Lock
    【解决方案3】:

    在不知道如何使用这段代码的情况下很难知道你的锁是否处于正确的级别,但如果你的外循环在单个线程中执行,它看起来没问题(除了因为你使用大写而难以阅读局部变量名,这使得一切看起来都像public)。在优化方面,您应该避免使用 lock 并改为实现 ReaderWriterLockSlim

    【讨论】:

    • 刚刚清理了变量。感谢您审查/引起我的注意。我得调查一下 ReaderWriterLockSlim
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-25
    • 2011-11-02
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多