Použití ThreadStatic pro kontext operace

Tomáš Holan       23. 4. 2012       Architektura, Threading       5847 zobrazení

Pokud potřebujeme nějaké operaci poskytnout data, občas se hodí, aby tyto data byla dostupná kdekoliv v kódu implementující danou operaci bez nutnosti předávat je parametrem apod. Platnost těchto dat je přitom ale logicky omezena jen na dobu vykonávání dané operace, takže by nebylo vhodné nebo při paralelním zpracování dokonce ani možné použití obyčejné statické proměnné. Za předpokladu, že je celé zpracování operace vykonáváno jen na jednom threadu, je docela elegantním řešením zavést kontext svázaný právě přímo s threadem.

Jak na to?

Řešení se skládá se dvou klíčových prvků. Prvním je použití ThreadStatic proměnné, ve které bude aktuální kontext držen a bude veřejně dostupný přes statickou vlastnost Current. Druhým je pak poskytnutí API umožňující jednoduché vymezení platnosti kontextu tj. inicializace a rušení kontextu. Aby pro tento účel šlo s výhodou použít blok using, je možné implementovat celý kontext jako disposable objekt.

Následující kód to ukazuje na třídě OperationContext, instanční data jsou zastoupena vlastností State:

public sealed class OperationContext : IDisposable
{
    #region member varible and default property initialization
    public object State { get; private set; }

    [ThreadStatic]
    private static OperationContext s_Current;
    #endregion

    #region constructors and destructors
    public OperationContext(object state)
    {
        if (state == null)
        {
            throw new ArgumentNullException("state");
        }
        if (s_Current != null)
        {
            throw new InvalidOperationException("Current thread's context is already set.");
        }

        this.State = state;
        s_Current = this;
    }
    #endregion

    #region action methods
    public void Dispose()
    {
        s_Current = null;
    }
    #endregion

    #region property getters/setters
    public static OperationContext Current
    {
        get { return s_Current; }
    }
    #endregion
}

Použití takto připravené třídy pak bude následující:

static void Main()
{
    //Infrastruktura - inicializace kontextu pro operaci
    using (new OperationContext("MyState"))
    {
        Operation();
    }
}

static void Operation()
{
    //Implementace vlastní operace - použití kontextu
    Console.WriteLine(OperationContext.Current.State);
}

Je vidět, že vlastní implementace tohoto “patternu” i jeho použití je poměrně jednoduché.

Všimněte si ještě, že naše uvedená implementace neumožňuje kontexty “vnořovat” (viz kontrola v konstruktoru třídy OperationContext). Pokud by to náš scénář vyžadovat, stačilo by implementovat ThreadStatic storage jako zásobník a aktuální kontext by pak byl vždy prvek na vrcholu tohoto zásobníku.

 

hodnocení článku

0       Hodnotit mohou jen registrované uživatelé.

 

Nový příspěvek

 

RE: Použití ThreadStatic pro kontext operace

V metodě Dispose bude s_Current vždy rovno this (nebo null při opakovaném volání) tj. jsme přímo v Dispose instance s_Current (s_Current je typu OperationContext). A OperationContext je disposable pouze pro "zneužití" bloku using pro vymezení platnosti kontextu.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

RE: Použití ThreadStatic pro kontext operace

Nebylo by vhodné v "Dispose" metodě kontrolovat, zda není s_Current také "IDisposable" a případně zavolat "Dispose" i na něm?

nahlásit spamnahlásit spam 0 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:  
Heslo:  

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback