Обновление ссылки на используемую переменную-член - PullRequest
0 голосов
/ 22 сентября 2008

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

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

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

Я знаю, что я просто обновляю ссылку, оставляя другой (старый) объект в памяти в ожидании сбора 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
    }
}

Ответы [ 4 ]

3 голосов
/ 22 сентября 2008

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

1 голос
/ 22 сентября 2008

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

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

0 голосов
/ 22 сентября 2008

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

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
    //}
}
0 голосов
/ 22 сентября 2008

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...