Можно ли заблокировать {часть} массива в C #? или есть динамический массив блокировки? - PullRequest
0 голосов
/ 11 октября 2011

У меня есть динамический список объектов, которые я отслеживаю, и в будущем я могу использовать много потоков.Может ли кто-нибудь посмотреть на эту реализацию на наличие ошибок?

Другими словами, я хочу отследить множество экземпляров этого объекта:

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

       }
   }
  }  

Видите ли вы недостатки в этой реализации?Есть ли лучший способ?

Ответы [ 3 ]

4 голосов
/ 11 октября 2011

Если вы используете .NET 4.0, вы можете использовать ConcurrentDictionary .

1 голос
/ 11 октября 2011

Трудно понять, находятся ли ваши блокировки на нужном уровне, не зная, как этот код будет использоваться, но если ваш внешний цикл выполняется в одном потоке, он выглядит нормально (кроме того, что его трудно читать, потому что вы используете верхний регистр) имена локальных переменных, из-за которых все выглядит public). При оптимизации следует избегать использования lock и использовать вместо него ReaderWriterLockSlim.

1 голос
/ 11 октября 2011

Да, вам нужно заблокировать var ActiveRow = BatchEntries[ThingToProcess];, потому что вы также добавляете в словарь (если вы не уверены, что они происходят в разное время). Если вы можете гарантировать, что не добавите, пока выполняется «внешний цикл», тогда нет, вам не нужно блокировать - у вас может быть одновременное чтение.

Если метод добавления происходит редко, с большим количеством операций чтения, вам следует изучить ReaderWriterLock

...