Kategorie szkoleń | Egzaminy | Kontakt
  • 1
  • 10
  • 316

W swojej aplikacji posiadam coś a’la wirtualną bazę danych, którą jest klasa singletone posiadająca referencje do paru kolekcji obiektów (komputery, użytkownicy, etc.), do których potrzebuje się odwoływać z różnych miejsc w aplikacji (asynchronicznie). Aplikacja dość mocno korzysta z threadów, z jednego threada kolekcja może być czytana, z innego updatowana, a z jeszcze innego mogą być usuwane obiekty z tej kolekcji. Usunięcie obiektu z enumerowanej kolekcji skutkuje wyjątkiem collection changed while enumerated, co stwarza potrzebę zastosowania lockowania, ale wtedy z asynchronicznej aplikacji zrobi się synchroniczna i zabije mi to wydajność. Czy macie jakiś pomysł, czym można zamienić tego singletona?

rafalsawer
  • Zapytał
  • @ rafalsawer | 14.12.2013
    • 10
    • 1
    • 2

Odpowiedź (1)

  • 7

Jednym z możliwych rozwiązań jest zastosowanie odpowiedniej strategii kontroli dostępu do kolekcji.

Zgodnie z sugestią zawartą w pytaniu blokowanie przy użyciu instrukcji lock może spowodować znaczny spadek wydajności.

W takim przypadku sugeruję przeanalizowanie zastosowań klasy ReaderWriterLock lub ReaderWriterLockSlim:

 

class DataItem
{
    public string Data;
}

class DbLocker
{
    ReaderWriterLockSlim locker = new ReaderWriterLockSlim();
    List<DataItem> DataList = new List<DataItem>(){new DataItem(){ Data="a"}, new DataItem() {Data="b"}};

    private DataItem UnsafeGetData(int index)
    {
        return DataList[index];
    }

    public void ChangeData(int index, string data)
    {
        locker.EnterWriteLock();

        try
        {
            DataItem Data = UnsafeGetData(index);
            Data.Data = data;
         
        }
        finally
        {
            locker.ExitWriteLock();
        }
    }

    public DataItem GetData(int index)
    {
        locker.EnterReadLock();  

        try
        {
            return UnsafeGetData(index);
        }
        finally
        {
            locker.ExitReadLock();
        }
    }

  
}

 

Aby uniknąć zgłaszania i obsługi wyjątku, można zastąpić metody Enter na wersje TryEnter.

Dodatkowo problem z wymienionym wyjątkiem może wynikać z iteracji za pomocą bloku foreach po dostępnej z wielu wątków kolekcji. W tym przypadku rozwiązaniem może być użycie for wraz ze sprawdzeniem granic indeksów kolekcji.

  • Odpowiedział
  • @ | 17.12.2013
  • TRENER ALTKOM AKADEMII