2016-10-28 25 views
5

Bir uygulamada, gerçek zamanlı olarak güncellenen olması gereken etki alanı nesneleri koleksiyonu var. Birkaç iş parçacığı, bu koleksiyonda bulunan 'daki öğeleri değiştiren bir işlem yapabilir ve bunu güvenle yapmalıdır. Şu anki yaklaşım, herhangi bir değişiklik yapmadan önce esas olarak küresel bir kilit alan, basitliğidir. Aşağıdaki gibi Az ya da çok bir şey: kilit çok iri olduğu içinHem öğe hem de koleksiyon düzeyinde kilitlemeyi etkin bir şekilde nasıl destekleyebilirim?

private readonly object lockObject = new object(); 
private Dictionary<int, Widget> items; 

private void UpdateAllWidgets() 
{ 
    lock (this.lockObject) 
    { 
     // Update all the widgets. No widgets should be permitted to be 
     // updated while this is running. 
    } 
} 

private void UpdateWidget(int widgetId) 
{ 
    lock (this.lockObject) 
    { 
     // Update the widget with id = widgetId. I want to me able to 
     // update other widgets at the same time, however. 
    } 
} 

Şimdi performansla sorunlarla çalıştırıyorum. Tek bir öğe güncellenmişken (diğer öğelerin aynı anda güncellenmesine izin verirken) öğe düzeyinde kilitler alabilmek istiyorum ancak yine de gerektiğinde koleksiyon düzeyinde bir kilit almak için 'u kullanabilirim. Bu destek olabilecek bir kilit yapısı üzerinde

Thread 1: UpdateWidget(1); 
Thread 2: UpdateWidget(2); // This can run before UpdateWidget(1) 
          // completes. 

Thread 1: UpdateWidget(1); 
Thread 2: UpdateAllWidgets(); // This has to wait for UpdateWidget(1) 
Thread 3: UpdateWidget(2); // This has to wait for UpdateAllWidgets() 
Thread 4: UpdateWidget(3); // This has to wait for UpdateAllWidgets(), but 
          // not UpdateWidget(2) 

Herhangi fikirler: Yani davranış aşağıdaki gibi görünecektir? Yukarıdaki örnek, basitleştirilmiş bir sürüm için gereklidir, ancak daha önce ConcurrentDictionary yetersiz kalmıştır. Örneğin, UpdateWidget içinde gerçekleştirilen eylemler, basit yerinde güncellemelerden daha fazlasıdır. Bu öğeyi etkileyen veritabanı güncellemelerini içerebilirler.

+0

Bu tür bir senaryona sahip olduğumda her iki yaklaşımı da kümülatırım. Bir ConcurrentDictionary, ancak her değeri bir kapsayıcıya sarmak, değişiklik yapmadan önce kilitleyebilirim. Toplama düzeyinde kilitleme işlemek için küresel bir ReaderWriterLockSlim eklemeniz gerekir –

+0

Koleksiyon öğeleri çok iş parçacıklı bir şekilde ekledi mi (veya kaldırıldı)? Veya koleksiyonun statik boyutu var ve öğeler yeni güncellendi mi? –

+0

@ MatiasCicero- Evet, öğeler başka konulara eklenip çıkarılabilir. Ekler, öğe düzeyinde güncellemeleri engellememelidir; Bir kaldırma işlemi yalnızca bu öğeyi engelleyecektir. –

cevap

3

Cevabımı, bu çok iş parçacıklı davranışı karşılaştırdığınızı ve tüm işi tek bir iş parçacığına göre sıralayacağınızı kabul ediyorum. Aksi takdirde, lütfen kilit çekişmesini tamamen önlemek için daha hızlı olduğunu fark edebilirsiniz.

Aradığınız şey, büyük olasılıkla ReaderWriterLockSlim .net adresinde bir okuyucu yazıcı kilidi. Tek bir öğeyi take a read lock, ardından lock() öğeyi güncelleştirmek için güncelleştirmeyi yapın ve lock()'u ve ardından okuma kilidini bırakın. "Tüm öğeler" güncellemesini yapmak için, bir ekleme veya kaldırma, özel olacak take a write lock.

+0

Bunu beğendim. Bu yaratıcı ve iş yapıyor. –