Manuelle Thread-Synchronisation

Die Verwendung mehrerer Abarbeitungspfade (Threads) innerhalb eines Prozesses erfordert diverse Maßnahmen zur Thread-Synchronisation, um Wettlaufsituationen auf gemeinsam genutzte Ressourcen zu unterbinden. In den meisten Fällen handelt es sich dabei um die Ressource Speicher.

Die lock-Anweisung

Ein Quellcodebereich kann beispielsweise mit Hilfe der lock-Anweisung als kritischer Abschnitt gekennzeichnet werden. Dafür muss eine Instanz eines Referenztyps als Sperrobjekt übergeben werden. Bereiche, die dasselbe Sperrobjekt verwenden, werden niemals gleichzeitig durchlaufen.

lock(m_SyncRoot)
{
  m_Sb.Append(...);
  ...
}

Der Einsatz von Sperren birgt immer ein Deadlock-Risiko. Blockierungen treten dann auf, wenn zwei Sperren in unterschiedlicher Reihenfolge benutzt werden. Solche Fehler sind schwer identifizierbar, da sie oft nur selten auftreten. Eine Maßnahme zur Fehlerreduzierung ist eine äußerst sparsame Verwendung von Sperren. Außerdem sollten Sperren nur in einem lokalen Kontext benutzt werden.

Sperren sind immer mit einem gewissen Overhead verbunden. Auch aus diesem Grund sollten Sperren nur dann verwendet werden, wenn es tatsächlich notwendig ist. Das folgende Beispiel zeigt eine sinnvolle Konstruktion bei der nur dann der kritische Bereich betreten wird, wenn das gewünschte Objekt noch nicht angelegt ist. Zu beachten ist die doppelte Überprüfung, da der Test nur im kritischen Bereich ein zuverlässiges Ergebnis liefert.

if(m_ThreadSafeObject==null)
{
  lock(m_SyncRoot)
  {
    if(m_ThreadSafeObject==null)
      m_ThreadSafeObject=new ThreadSafeObject()
  }
}

Das gezeigte Beispiel hat letztendlich nur den Effekt, dass das Objekt immer nur von einem Thread angelegt wird. Ohne die Sperre könnten mehrere Threads gleichzeitig ein Objekt erzeugen und der Member-Variablen zuweisen.

Spezielle Maßnahmen

Das .NET Framework beinhaltet eine interessante Klasse zur Synchronisation von Threads, die gleichzeitige Lesezugriffe erlaubt. Schreibzugriffe hingegen erfolgen immer exklusiv. Die Klasse ReaderWriterLock aus dem Namensraum System.Threading sorgt so für eine höhere Abarbeitungsgeschwindigkeit, insbesondere dann, wenn Lesezugriffe gegenüber Schreibzugriffen überwiegen.

Ähnliche Artikel

Schreiben Sie einen Kommentar