0

このシングルキャッシュオブジェクトを取得しました。これにより、プライベートIEnumerable変数を返すだけのIEnumerableプロパティが公開されます。

このメンバー変数(このキャッシュオブジェクトの単一の「インスタンス」インスタンスに存在する)を更新する静的メソッドがシングルトンオブジェクトにあります。

キャッシュが更新されている間、あるスレッドが現在この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

4 に答える 4

3

{ return sektioner; }新しい値がフィールドに入力される前にゲッターが呼び出されるため、古い値が返されます。次に、ループforeach (Sektion s in cache.Sektioner)は、ゲッターが呼び出されたときに受信した値、つまり古い値を使用します。その値は、foreachループ全体で使用されます。

于 2008-09-22T10:42:16.877 に答える
1

現在 sektioner を列挙しているスレッドは、シングルトン内の参照を更新しても引き続き列挙します。IEnumerable を実装するオブジェクトについて特別なことは何もありません。

読み取りロックを提供しておらず、複数のスレッドが読み取り/書き込みを行っているため、おそらくvolatileキーワードを sektioner フィールドに追加する必要があります。

于 2008-09-22T10:47:14.867 に答える
0

まず、オブジェクトのロックが見られず、未使用の lockObject 変数が悲しいです。IEnumerable は特別なものではありません。各スレッドには、sektioner オブジェクトのインスタンスへの参照の独自のコピーがあります。そのように他のスレッドに影響を与えることはできません。sektioner フィールドが指す古いバージョンのデータがどうなるかは、発呼側に大きく依存します。

于 2008-09-22T10:45:23.560 に答える
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
    //}
}
于 2008-09-22T12:05:54.193 に答える