Frage

Ich habe diesen Singleton Cache-Objekt, und es macht eine IEnumerable Eigenschaft, die nur eine private IEnumerable Variable gibt.

Ich habe eine statische Methode auf meinem Singleton-Objekt, das dieses Membervariable aktualisiert (das gibt sich auf der Single ‚Instanz‘ Instanz dieses Cache-Objekts).

Lassen Sie uns sagen einige Thread derzeit über diese IEnumerable Variable / Eigenschaft iteriert, während meine Cache-Aktualisierung wird. Ich habe es so der Cache auf eine neue lokale Variable aktualisiert wird und schließlich die freiliegende private Variable Einstellung auf diese neue lokale Variable verweisen.

Ich weiß, ich bin nur eine Referenz zu aktualisieren, warten auf das andere (alte) Objekt im Speicher zu verlassen von der GC abgeholt zu werden, aber mein Problem ist - ich bin nicht 100% sicher, was passiert, wenn ich die neue Referenz gesetzt ? Wäre der andere Thread plötzlich Iterieren sein über das neue Objekt oder die alten es durch die IEnumerable-Schnittstelle übergeben wurde? Wenn es eine normale Referenz gewesen hätte, würde ich sagen ‚Nein‘. Der aufrufende Thread würde auf dem alte Objekt in Betrieb sein, aber ich bin nicht sicher, ob dies der Fall für IEnumerable ist auch?

Hier wird die Klasse abgespeckte:

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
    }
}
War es hilfreich?

Lösung

Der Faden, der zur Zeit sektioner wird Aufzählen wird es weiterhin auch aufzuzählen, wenn Sie die Referenz in der Singleton aktualisieren. Es ist nichts Besonderes über Objekte, die IEnumerable implementieren.

Sie sollten vielleicht die flüchtigen Stichwort zum sektioner Feld, da Sie nicht lesen Hemmung bereitstellen und mehr Threads lesen / zu schreiben.

Andere Tipps

Da die Getter { return sektioner; } aufgerufen wird, bevor der neue Wert im Bereich gesetzt wird, wird der alte Wert zurückgegeben. Dann verwendet die Schleife foreach (Sektion s in cache.Sektioner) den Wert, der erhalten wurde, wenn der Getter genannt wurde, das heißt den alten Wert. Dieser Wert wird während der foreach-Schleife verwendet werden.

Zunächst einmal kann ich nicht Objekt sperren, nicht verwendete LockObject Variable macht mich traurig sehen. IEnumerable ist nichts Besonderes. Jeder Thread wird seine eigene Kopie der Bezugnahme auf einen Fall von sektioner bezwecken. Sie können nicht andere Threads beeinflussen auf diese Weise. Was mit alten Version von Daten darauf durch sektioner Feld weitgehend abhängig Anrufers.

passieren würde,

Ich denke, wenn Sie eine Thread-Sicherheit wollen, sollten Sie auf diese Weise verwenden:

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
    //}
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top