Обновление ссылки на используемую переменную-член

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

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

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

Я знаю, что просто обновляю ссылку, оставляя другой (старый) объект в памяти, ожидающий, чтобы его взял сборщик мусора, но моя проблема в том, что я не на 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
    }
}
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
318
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

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

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

Per Hornshøj-Schierbeck 22.09.2008 14:46

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

Блокировка находится в разделе «SNIP» моего UpdateCache :)

Per Hornshøj-Schierbeck 22.09.2008 14:48
Ответ принят как подходящий

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

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

Экземпляр, который он перечисляет, не обязательно должен быть новым (и ключевым словом volatile)? Я имею в виду, что я сделал его IEnumerable, чтобы он ничего не мог изменить, или мне что-то здесь не хватает?

Per Hornshøj-Schierbeck 22.09.2008 14:49

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

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
    //}
}

Другие вопросы по теме