Philippe Bénard
Software Architect

3 Wege zu Threadsicherem Code


In den Zeiten von Service Orientierter Programmierung gibt es ganz andere Anforderungen an die Softwaresysteme als noch vor einigen Jahren. Entwickler müssen sich Gedanken machen wie Sie Ihren Code gestalten und wie zum Beispiel der Context zu einer Datenbank sicher designed werden muss.

Man stelle sich folgendes Scenario vor:
Sie haben verschiedene Services die aus einer Datenbankinstanz Daten konsumieren und updaten.


Der Datenbankcontext wird nach jedem Aufruf eines Services verworfen und bei jedem Aufruf neu geöffnet, um Nebeneffekte wie zum Beispiel das unbeabsichtigte ändern einer Datenbankentität zu vermeiden.

Solange nur ein Client den Aufruf tätig, stellt dieses Scenario kein Problem dar. Sollte jedoch ein zweiter Client einen Aufruf gegen einen Service tätigen und Sie den gleichen Datenbankcontext wie der erste Client verwenden, kann es unter Umständen zu Fehler führen.


Der Fehler liegt auf der Hand – sobald Client1 den Datacontext per Request öffnet und Client2 nur millisekunden später darauf zugreift, sharen sich beide den gleichen Datacontext. Sollte nun Client1 seine Transaktionen beendet haben wird der Context geschlossen, Client2 jedoch versucht während seines Prozess auf den geschlossenen Context zuzugreifen und es wird ein Fehler geworfen.

Um dies zu vermeiden müssen wir sicherstellen, dass jeder Aufruf seinen eigenen Context bereitgestellt bekommt.

Hierzu stelle Ich Ihnen nun 3 Wege vor einen Threadsicheren Aufruf zu Gewährleisten (Es handelt sich hierbei um Pseudocode)


HttpContext


public DataContext GetDataContext()
{
   if (!HttpContext.Current.Items.Contains("DataContext"))
   {
      DataContext context = new DataContext();              
      HttpContext.Current.Items.Add("DataContext", context);
   }
   return HttpContext.Current.Items["DataContext"] as DataContext;
}


Sie speichern hierbei den Datacontext in dem aktuellen HTTPContext wodurch welcher nur für diesen Client zur Verfügung steht.
Ein Nachteil dieser Technik ist, dass es nur in Webanwendungen mit einem HttpContext funktioniert.


Thread-NamedDataSlot


private const string SLOT = "DataContext";
private LocalDataStoreSlot slot;
private TransactionScope context;


public DataContext()
{
  if (Thread.GetNamedDataSlot(SLOT) == null)
  {
    Thread.AllocateNamedDataSlot(SLOT);
    context = new DataContext();
    slot = Thread.GetNamedDataSlot(SLOT);
    Thread.SetData(slot, context);     
  }


     

public static DataContext CurrentDataContext
{
   get
   {
     if (Thread.GetNamedDataSlot(SLOT) != null)
     {
        LocalDataStoreSlot slot = Thread.GetNamedDataSlot(SLOT);
        if (Thread.GetData(slot) != null)
                 return Thread.GetData(slot) as DataContext;
     }
 
     throw new Exception("Please initialize the DataContext using a 'using' Statement.");
   }
}


public void Dispose()
{
    context.Dispose();
    Thread.FreeNamedDataSlot(SLOT);
}


Hier wird der Context im aktuellen Thread hinterlegt. Wichtig ist, dass über Thread.FreeNamedDataSlot(SLOT) der Speicher wieder freigegeben wird.
Der Vorteil hierbei ist, dass diese Herangehensweise auch außerhalb von Webanwendungen funktioniert und keine Prozesse blockiert.


Singleton & Lock


private static object sync = new object();
private static volatile DataContext ctx;



// Doublecheck.
public static DataContext GetDataContext()
{
   if (ctx == null)
   {
     lock (sync)
     {
       // Double check to avoid concurrency issues.
       if (ctx == null)
           ctx = new DataContext();
     }
   }
   return ctx;
}


Hierbei wird ein paralleler Aufruf auf den DataContext blockiert und wartet darauf bis die Ressource wieder freigegeben wird.
Nachteil hierbei ist, dass die Performance darunter leiden kann, wenn sehr viele Aufrufe auf das Objekt stattfinden, da der Aufrufende Thread warten muss bis die Ressource freigegeben wurde.

Gruß

Phil

Kommentare
Es wurden noch keine Kommentare zu diesem Eintrag geschrieben.
Kommentar hinzufügen
Vor und Zuname
E-Mail
E-Mail bei weiteren Kommentaren
Mein Kommentar