Teil 1: Singleton und InitOnce

Parallel Computing
Kommentare

Wie auch bei der objektorientierten Programmierung sollten bei der Umsetzung paralleler Lösungen erprobte Entwurfsmuster (Design Pattern) eingesetzt werden. Die hiermit beginnende kleine Serie gibt einen Überblick über Entwurfsmuster aus dem Bereich Parallel Computing und ihre Umsetzungsmöglichkeiten mit der Task Parallel Library.

Die Task Parallel Library stellt nicht nur reine API-Erweiterungen für die parallele Programmierung bereit, sondern beinhaltet ein Programmiermodell, das bereits teilweise einige Entwurfsmuster fast vollständig zur Verfügung stellt. Der erste Teil dieser kleinen Serie widmet sich dem Thema „Einmaligkeit“. Hierbei bezieht sich „Einmaligkeit“ auf Objektinstanzen sowie auf einzelne Variablenwerte, und ist nicht nur für parallele Anwendungen interessant, sondern teilweise auch für sequenzielle Anwendungen.

Singleton

Ein sehr bewährtes und schon seit geraumer Zeit erfolgreich verwendetes Entwurfsmuster ist das Singleton-Muster [1]. Es gehört gleichzeitig auch zu den einfachsten Mustern. Dennoch existieren hierfür verschiedenartige Realisierungsmöglichkeiten. Innerhalb einer sequenziellen Anwendung mit nur einem Thread können fast alle möglichen Realisierungsformen verwendet werden. Für eine parallele Anwendung mit mehr als einem Thread sind jedoch nur bestimmte Implementierungsformen verwendbar. Die generelle Funktionsweise eines Singleton besteht darin sicherzustellen, dass von einer Klasse nur eine Instanz existiert. Somit limitiert ein Singleton die Erzeugung von Objektinstanzen. Im klassischen Fall kann nur eine Instanz eines Objekttypen erzeugt werden. Darüber hinaus existieren auch Formen, die die Anzahl aktiver Objekte auf eine bestimmte Zahl einschränken. Singletons können sehr leicht umgesetzt werden, jedoch müssen immer die Rahmenbedingungen beachtet werden. In Multithread-Umgebungen muss z. B. das Muster threadsafe umgesetzt werden. Kernbestandteil des Musters ist das Objekt selbst, das als Singleton umgesetzt werden soll. Abbildung 1 zeigt das entsprechende Klassendiagramm des Entwurfsmusters, während Listing 1 die einfachste und zugleich auch unsicherste Form einer Singleton-Realisierung innerhalb einer parallelen Anwendung demonstriert.

Abb. 1: Klassendiagramm Singleton
Abb. 1: Klassendiagramm Singleton

Listing 1
public class Singleton
{
    private static Singleton self = null;
    private Singleton() { }
    public static Singleton Create
    {
        get
        {
            if (self==null)
                self = new Singleton();
            return self;
        }
    }
}
  

Um die Objekterzeugung von außen verhindern zu können, muss der Konstruktor der Klasse als private gekennzeichnet werden. Nach dieser kleinen Änderung ist sichergestellt, dass es nicht möglich ist, ein Objekt der Klasse per new zu erzeugen. Der aktuelle Zustand des Objekts, ob es also bereits angelegt wurde oder nicht, muss der Klasse bekannt sein. Dazu wird eine statische (static) Variable vom umgebenden Typ in der Klasse definiert. Diese Variable muss statisch (static) deklariert werden, da auf sie zugegriffen werden muss, wenn noch keine konkrete Objektinstanz vorhanden ist. Da kein öffentlicher Konstruktor zur Objektanlage von außen genutzt werden darf, muss eine statische Methode erstellt werden. Im vorliegenden Beispiel dient die Methode Create dazu. Die Methode muss statisch sein, da sie nicht an eine bestimmte Objektinstanz gebunden ist. Die Methode Create ist für die Anlage des Objekts verantwortlich. Dabei kontrolliert sie, ob bereits eine Instanz des Objekts vorhanden ist oder nicht. Ist bereits eine Instanz angelegt worden, wird diese dem Aufrufer zurückgegeben. Ist noch keine Instanz vorhanden, wird eine neue erzeugt und dem Aufrufer zurückgegeben.

Singleton in multithreaded Umgebungen

Die gezeigte Singleton-Implementierung aus Listing 1 kann problemlos bei sequenziellen Anwendungen mit nur einem Thread verwendet werden. Sind mehr Threads gleichzeitig aktiv, muss die Implementierung allerdings erweitert werden. Das Problem liegt in der if-Abfrage ( if self==null). Nach der Abfrage besteht die Möglichkeit, dass der aktive Thread unterbrochen wird und ein anderer Thread danach die Singleton-Instanz anfordert und anlegt. Wird dann der zuvor angehaltene Thread fortgesetzt, legt er ebenfalls eine neue Instanz an. Um dies zu vermeiden, muss dafür gesorgt werden, dass die Abfrage und die unter Umständen anschließende Objekterstellung nicht unterbrochen werden können. Um dies sicherzustellen, ist eine Sperre (lock) um die Abfrage herum vorzusehen (Listing 2).

Listing 2
class SingletonThreadSafe
{
    private static SingletonThreadSafe self = null;
    static readonly object threadLock = new object();
    private SingletonThreadSafe() {}
    public static SingletonThreadSafe Create
    {
        get
        {
            lock (threadLock)
            {
             if (self==null)
                self = new SingletonThreadSafe();
            }
            return self;
        }
    }
}
  

Durch die eingesetzte Sperre wird garantiert, dass nur ein Thread die Abfrage und eventuelle Erzeugung gleichzeitig durchführen kann. Um die Performance des Singleton zu verbessern, kann die Abfrage – ob die Instanz schon existiert – vor der Sperre durchgeführt werden. Somit muss nicht für jede Prüfung die Sperre frei sein. Dies bedeutet aber auch, dass innerhalb der Sperre noch einmal der Zustand der Objektinstanz überprüft werden muss (Listing 3). Da nun die erste Abfrage ohne Sperre erfolgen kann, ergibt sich ein besseres Laufzeitverhalten.

Listing 3
class SingletonThreadSafe
{
    private static SingletonThreadSafe self = null;
    static readonly object threadLock = new object();
    private SingletonThreadSafe() {}
    public static SingletonThreadSafe Create
    {
        get
        {
          if (self==null)
          {
            lock (threadLock)
            {
             if (self==null)
                self = new SingletonThreadSafe();
            }
          }
          return self;
        }
    }
}
  
Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -