2008-09-22 4 views
0

Я получил этот объект кэширования síngleton, и он предоставляет свойство IEnumerable, которое возвращает частную переменную IEnumerable.Обновление ссылки на переменную-член, которая используется

У меня есть статический метод для моего объекта singleton, который обновляет эту переменную-член (которая существует в экземпляре экземпляра «экземпляр» этого объекта кеша).

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

Я знаю, что я просто обновляю ссылку, оставляя другой (старый) объект в памяти ожидающим, чтобы его подхватил GC, но моя проблема - я не уверен на 100%, что происходит, когда я устанавливаю новый Справка? Будет ли другой поток неожиданно повторять новый объект или старый, который он прошел через интерфейс IEnumerable? Если бы это была нормальная ссылка, я бы сказал «нет». Вызывающий поток будет работать на старом объекте, но я не уверен, что это также относится к IEnumerable?

Вот класс урезанная:

internal sealed class SektionCache : CacheBase 
{ 
    public static readonly SektionCache Instance = new SektionCache(); 
    private static readonly object lockObject = new object(); 
    private static bool isUpdating; 

    private IEnumerable<Sektion> sektioner; 

    static SektionCache() 
    { 
     UpdateCache(); 
    } 

    public IEnumerable<Sektion> Sektioner 
    { 
     get { return sektioner; } 
    } 

    public static void UpdateCache() 
    { 
    // SNIP - getting data, locking etc. 
    Instance.sektioner = newSektioner; 
    // SNIP 
    } 
} 

ответ

1

Нить, которая в настоящее время перечисляет sektioner, будет продолжать перечислять ее, даже когда вы обновляете ссылку в синглетоне. Нет ничего особенного в объектах, которые реализуют IEnumerable.

Возможно, вы должны добавить ключевое слово volatile в поле sektioner, поскольку вы не предоставляете блокировку чтения, а несколько потоков читают/записывают его.

+0

Экземпляр, который он перечисляет, не обязательно должен быть новым (и ключевым словом volatile)? Я имею в виду, что я сделал его IEnumerable, чтобы он ничего не мог с этим поделать, или я что-то пропустил здесь? – 2008-09-22 10:49:30

3

Поскольку геттер { return sektioner; } вызывается перед тем, новое значение помещается в поле, старое значение возвращается. Затем в цикле foreach (Sektion s in cache.Sektioner) используется значение, полученное при вызове геттера, то есть старое значение. Это значение будет использоваться в течение цикла foreach.

+0

Да, это то, что я думаю, тоже, как и в любом другом случае, но это частный случай поднял вопрос во время обзора моего объекта, поэтому я хотел убедиться, что я ничего не пропустил. – 2008-09-22 10:46:39

0

Прежде всего я не вижу блокировки объектов, неиспользуемая функция lockObject заставляет меня грустить. IEnumerable не является особенным. Каждый поток будет иметь свою собственную копию ссылки на какой-либо экземпляр объекта sektioner. Вы не можете воздействовать на другие потоки таким образом. То, что произойдет со старой версией данных, указанное полем sektioner, во многом зависит от вызывающей стороны.

+0

Блокировка находится в разделе «SNIP» моего UpdateCache :) – 2008-09-22 10:48:00

0

Я думаю, если вы хотите безопасности потока, вы должны использовать этот путь:

internal sealed class SektionCache : CacheBase 
{ 
    //public static readonly SektionCache Instance = new SektionCache(); 

    // this template is better (safer) than the previous one, for thread-safe singleton patter >>> 
    private static SektionCache defaultInstance; 
    private static object readonly lockObject = new object(); 
    public static SektionCach Default { 
     get { 
      SektionCach result = defaultInstance; 
      if (null == result) { 
       lock(lockObject) { 
        if (null == result) { 
         defaultInstance = result = new SektionCache(); 
        } 
       } 
      } 

      return result; 
     } 
    } 
    // <<< this template is better (safer) than the previous one 

    //private static readonly object lockObject = new object(); 
    //private static bool isUpdating; 
    //private IEnumerable<Sektion> sektioner; 

    // this declaration is enough 
    private volatile IEnumerable<Sektion> sektioner; 

    // no static constructor is required >>> 
    //static SektionCache() 
    //{ 
    // UpdateCache(); 
    //} 
    // <<< no static constructor is required 

    // I think, you can use getter and setter for reading & changing a collection 
    public IEnumerable<Sektion> Sektioner { 
     get { 
      IEnumerable<Sektion> result = this.sektioner; 
      // i don't know, if you need this functionality >>> 
      // if (null == result) { result = new Sektion[0]; } 
      // <<< i don't know, if you need this functionality 
      return result; 
     } 
     set { this.sektion = value; } 
    } 

    //public static void UpdateCache() 
    //{ 
    //// SNIP - getting data, locking etc. 
    //Instance.sektioner = newSektioner; 
    //// SNIP 
    //} 
} 
Смежные вопросы