/*
     *  Copyright (c) Januar 2005 Jean Gressmann (jsg@rz.uni-potsdam.de)
     *
     *  Einige Beispiele zur Benutzung der Thread-Klassen
     *
     */
    
    #ifdef _MSC_VER
        #pragma warning(disable:4786)
        #pragma warning(disable:4503)
    #endif
    
    #include <iostream>
    #include <fstream>
    #include <string>
    #include <cassert>
    #include <deque>
    #include <list>
    #include <ctime>
    #include <cstdlib>
    #include <cstdio>
    #include <set>
    #include <portablethreads/mutex.h>
    #include <portablethreads/condition.h>
    #include <portablethreads/thread.h>
    #include <portablethreads/thread_pool.h>
    #include <portablethreads/tsallocator.h>
    #include <portablethreads/message_queue.h>
    #include <portablethreads/utility.h>
    #include <portablethreads/atomic_number.h>
    #include <portablethreads/lock_free.h>
    #ifdef _MSC_VER
        #include <crtdbg.h>
    #endif
    
    using namespace std;
    using namespace PortableThreads;
    
    
    // Hello World Beispiel
    // 
    // Ein Thread, der "Hello World" ausgibt, wird erzeugt.
    // Um Threads benutzen zu können, muss die Klasse die "threadable"
    // sein soll, von PThread erben und die pure virtual Methode
    // void threadImpl(); überschreiben. In der Basisklasse PThread
    // sind einige Methoden enhalten, die den Ablauf von Threads steuern.
    // 
    // 1.   bool run(); -> durch ein Aufruf dieser Methode wird ein 
    //      Thread gestartet. Es ist durchaus möglich mehrere Threads
    //      pro Objekt laufen zu lassen (durch wiederholten Aufruf von run()),
    //      allerdings kann dann sehr schnell Verwirrung auftreten. 
    //      Ich empfehle daher pro Thread ein eigenes Objekt anzulegen.
    //      HINWEIS: Die run()-Methode kehrt sofort zurück und wartet nicht,
    //      bis der Thread zum erstem Mal die threadImpl()-Methode betreten hat.
    // 2.   void Stop(); -> Bricht den laufenden Thread sofort ab. Diese 
    //      Methode sollte benutzt werden um Threads vorzeitig zu beenden,
    //      da Threads, die auf diese Weise terminiert werden, DLLs, Dateien
    //      usw. in einem ungültigen Zustand hinterlassen können.
    // 3.   void join(); -> Wartet auf die Beendigung eines Threads. Diese 
    //      Methode blockiert den Aufrufer so lange, bis der laufende Thread
    //      geendet hat. Diese Methode kann nur aufgerufen werden, wenn 
    //      nicht bereits void Detach(); aufgerufen wurde.
    // 4.   void Detach(); -> Überführt einen Thread in den "detached" Zustand.
    //      In diesem Zustand können die Resourcen des Threads nach seiner 
    //      Beendigung wiederverwendet werden. Allerdings kann dann auch nicht
    //      mehr auf die Beendigung des Threads mit void join(); gewaretet werden.
    // 5.   void Give(); -> Teilt dem laufenden Thread mit, den Prozessor für 
    //      andere Threads freizumachen.
    // 6.   bool operator==(const PThread& o) const;        
    //      bool operator!=(const PThread& o) const;
    //      Operatoren um Threads auf Gleichheit und Ungleichheit zu testen.
    
    namespace Beispiel1
    {
        class HelloWorld : public PThread
        {
            // Einstiegsmethode für den Thread
            void threadImpl()
            {
                cout << "Hello World" << endl;
            }
        };
    }
    
    void beispiel1()
    {
        cout << "Hello World Beispiel. ";
        cout << "Press enter to start" << endl;
        cin.get();
    
        using namespace Beispiel1;
    
    
        HelloWorld t;
        // Startet den Thread
        t.run();
        // Wartet bis der Thread beendet ist. Wird nicht gewartet,
        // erscheint höchstwahrscheinlich keine Ausgabe, da alle
        // Threads mit dem Hauptthread (der main-Funktion) beendet 
        // werden.
        t.join();
    }
    
    /*****************************************************************************/
    
    // Weitere "Hello World" Beispiele
    //
    // In diesen Beispiel wird gezeigt, wie man Threads in den Griff bekommt,
    // indem man sie mit Objektsemantik versieht. Objektsemantik bedeutet konkret,
    // dass der Thread nach Aufruf der start()-Methode vor dem Ausführen des
    // Destruktors wenigstens einmal läuft.
    // PThreadObjektSemantik ist eine Policy-based Klasse. Die Policy spezifiziert
    // wie oft der Thread den Funktionsoperator (= operator()) aufrufen soll. Es gibt drei
    // fertige Policies:
    // 1.   runOnce -> Thread läuft höchstens einmal
    // 2.   template<unsigned int> runN -> Thread läuft höchstens N mal
    //      N kann auch 0 sein
    // 3.   runForever -> der Thread läuft so lange bis entweder der Destruktor
    //      von PThreadObjectSemantic aufgerufen wird, oder er mit shutdown()
    //      beendet wird.
    // Es ist natürlich auch mögliche eingene Policies zu definieren. Policies sind
    // Klassen, welche die folgenden drei Memberfunktionen bereitstellen müssen:
    // 1.   void reset(); -> versetzt die Policy in einen definierten Startzustand
    // 2.   bool next(); -> wird in jeder Iteration evaluiert. Über diese Methode 
    //      wird gesteuert, wie oft der Thread läuft (genauer wie oft loopImpl() 
    //      aufgerufen wird
    // 3.   void shutdown(); -> Nachdem diese Methode aufgerufen wurde, muss der
    //      nächste Aufruf von next() false liefern.
    // Eine Klasse, die PThreadObjectSemantic nutzen möchte, muss über eine Standard-
    // konstruktor verfügen UND den Funktionsoperator operator()() public definieren.
    
    namespace Beispiel1_1
    {
        class HelloWorld
        {
        protected:
            void operator()()
            {
                cout << "Hello World" << endl;
            }
        };
        
        typedef PThreadObjectSemantic<HelloWorld, RunForever> HelloWorldForever;
        class StopHelloWorld
        {
            HelloWorldForever& hello_;
        protected:
            void operator()()
            {
                hello_.shutdown(false);
            }   
        public:
            StopHelloWorld(HelloWorldForever& h)
                :   hello_(h)
            {}
        };
    }
    
    void beispiel1_1()
    {
        cout << "Hello World Beispiel mit einen Thread, der Objektsemantik besitzt. ";
        cout << "Press enter to start" << endl;
        cin.get();
        
        using namespace Beispiel1_1;
        
        // Default Policy ist runOnce
        typedef PThreadObjectSemantic<HelloWorld> HelloWorldOne;
        
        cout << "Ein mal Hello Word ausgeben" << endl;
        try
        {
            HelloWorldOne hello;
            hello.start();
        }
        catch(...)
        {
            assert(false && "This shouldn't have happened. Check implementation!");
        }
        // Das Template Argument zu runN gibt die Anzahl der Iterationen an
        typedef PThreadObjectSemantic<HelloWorld, RunN<5> > HelloWorld5;
        cout << "Fünf mal Hello Word ausgeben" << endl;
    
        try
        {
            HelloWorld5 hello5;
            hello5.start();
        }
        catch(...)
        {
            assert(false && "This shouldn't have happened. Check implementation!");
        }
        
        typedef PThreadObjectSemantic<StopHelloWorld> Stopper;
        cout << "Für immer Hello World" << endl;
    
        try
        {
            // Starte Thread ....
            HelloWorldForever forever;
            forever.start();
            // der ewig läuft ....
            Stopper stop(forever);
            stop.start();
            // jetzt haben wir genug und beenden den Thread
            cout << "Genug Hello World" << endl;
        }
        catch(...)
        {
            assert(false && "This shouldn't have happened. Check implementation!");
        }
    }
    
    
    /*****************************************************************************/
    
    // PingPong Beispiel - ein Klassiker
    // 
    // In diesem Beispiel geht es um rudimentäre Threadsynchronisation.
    // Zwei Threads, Ping und Pong, spielen sich gegenseitig einen 
    // Ball zu (hier einen bool-Variable). Da immer nur ein Thread den 
    // Ball gleichzeitig haben darf, muss der Zugriff synchronisiert werden.
    // Die Snychronisation wird durch das Dreiergespann TSAllocator, TSProxy
    // und (No)LockPointer realisiert. 
    // 
    // TSAllocator - Allokation
    // Da selbst die Datenallokation mit Threads
    // schwierig werden kann, übernimmt die Klasse TSAllocator diese Aufgabe.
    // Soll z.B. der bool allokiert werden so wird die Create()-Methode von 
    // TSAllocator aufgerufen. Der bool'sche Wert wird thread-safe allokiert
    // und unter einem Schlüssel gespeichert. Der Datentyp des Schlüssels
    // kann über das Template Argument der TSAllocator Klasse angegeben werden.
    // Datentypen, die über den TSAllocator verwaltet werden sollen müssen
    // zwingend über einen Copy-Konstruktor verfügen.
    // Um die allokierte Variable zu nutzen ruft man die Methode Reference() 
    // auf. Sie liefert eine "Referenz" auf die Variable zurück.
    // Eine nicht länger benötigte allokierte Variable kann durch einen Aufruf
    // von Destroy() wieder gelöscht werden.
    // Der TSAllocator sollte aber nie direkt genutzt werden, sondern nur
    // indirekt durch die Klasse TSProxy.
    // 
    // TSProxy - Allokation, Deallokation
    // TSProxy ist dient dazu Variablen, deren Zugriff synchronisiert werden muss
    // thread-safe anzulegen, zu referenzieren und zu löschen. 
    // Der Konstruktor von TSProxy
    //      template<Schlüsseltyp, Werttyp> TSProxy(Schlüssel, const Wert& copy, TSAllocator alloc)
    // 
    // erzeugt eine Variable vom Typ >>Werttyp<< unter dem Schlüssel >>Schlüssel<<. 
    // Diese Variable existiert so lange im TSAllocator, bis das letzte (referenzgezählt)
    // TSProxy-Objekt, welches genau diesen Schlüssel verwendet, zerstört wird. 
    // Jedes TSProxy-Objekt dient quasi als Anker für die allokierte Variable. 
    // Mittels der TSProxy Klasse können verschiedene Threads ein und die selbe Variable
    // referenzieren, ohne dass der genaue Allokationsort (also die Adresse)
    // den Threads bekannt sein muss. Es ist damit nicht mehr notwendig, 
    // jedem Thread einen Zeiger auf die Variable o.ä. mitzugeben.
    // Im Konstruktor muss nur der Schlüssel angegeben werden. Die anderen
    // Parameter haben default-Werte. Wird kein Wert (Parameter 2) angegeben,
    // ruft TSProxy den Standard-Konstruktor für diesen Datentyp auf. Der letzte
    // Parameter spezifiziert, welcher TSAllocator genutzt werden soll. Wird kein
    // Allocator angegeben, wird der globale TSAllocator TSA genutzt.
    // Der Konstruktor von TSProxy erzeugt also entweder ein neues Objekt 
    // in einem TSAllocator und/oder erhöht dessen Referenzzähler.
    // Nachdem mit dem TSProxy eine "Referenz" auf eine Variable angelegt wurde
    // kann mit den Klassen (No)LockPointer diese benutzt werden.
    // 
    // Zugriff - (No)LockPointer
    // Den eigentlichen Zugriff auf die allokierte und referenzierte Variable erhält
    // man durch die die Klassen LockPointer und NoLockPointer. Beide Klassen 
    // erhalten im Konstruktor eine Referenz auf einen TSProxy. Über diese Referenz
    // werten sie die Referenz aus und gelangen zu EXKLUSIVEM (LockPointer) und
    // NICHT EXKLUSIVEM (NoLockPointer) Zugriff auf die Variable. Im Falle von 
    // LockPointer bleibt die gemeinsame Variable für die Lebenszeit des 
    // LockPointer-Objekts für andere Threads gesperrt.
    // Warum NoLockPointer? Manche Klasse sind von sich aus synchronisiert, das
    // heißt gegen gleichzeiten Zugriff geschützt (gilt für keine STL Klasse). 
    // Für Objekte dieser Klassen eine zusätzliche Synchronisation mittels
    // LockPointer zu sichern ist ein unnötiger Overhead.
    
    
    namespace Beispiel2
    {
        // Konstante zum Referenzieren der globalen Variablen
        // Hinweis: Hier, wie auch in allen anderen Beispielen, wird der 
        // globale TSAllocator TSA genutzt.
        const string PINGPONG = "PingPong";
    
        class Ping : public PThread
        {
            void threadImpl()
            {
                // Erzeuge/referenziere die gemeinsame booleansche
                // Variable. In diesem Fall ist es unwichtig,
                // welcher Thread die Variable letztendlich 
                // erzeugt.
                TSProxy<string, bool> sharedVar(PINGPONG);
    
                for(int i = 0; i < 10; ++i)
                {
                    // Synchronisierten Zugriff auf die Variable...
                    // Falls das Flag nicht setzt ist, war 
                    // der Pong-Thread noch nicht dran, also
                    // warten wir.
                    // Die gemeinsame bool'sche Variable wird 
                    // nur zum Testen ihres Wertes gesperrt.                
                    while(!*LockPointer<bool>(sharedVar))
                        give();
                    
                    // exklusiven Zugriff auf die Variable sichern.
                    LockPointer<bool> lockedSharedVar(sharedVar);
                    // setze das Flag auf false und signalisiere
                    // dem Pong-Thread so, dass er dran ist.
                    *lockedSharedVar = false;
                    cout << "Ping " << *lockedSharedVar << endl;
                    // Hier wird der LockPointer lockedSharedVar zerstört 
                    // und die bool'sche Variable für andere Threads
                    // freigegeben.
                }
            }
        };
    
        class Pong : public PThread
        {
            void threadImpl()
            {
                TSProxy<string, bool> sharedVar(PINGPONG);
    
                for(int i = 0; i < 10; ++i)
                {
                    // falls das Flag gesetzt ist, war
                    // Ping noch nicht dran ...
                    while(*LockPointer<bool>(sharedVar))
                        give();
                        
                    LockPointer<bool> lockedSharedVar(sharedVar);
                    *lockedSharedVar = true;
                    cout << "Pong " << *lockedSharedVar << endl;                
                }
            }
        };
    }
    
    
    void beispiel2()
    {
        cout << "Ping Pong Beispiel mit einem booleanschen Flag. ";
        cout << "Press enter to start" << endl;
        cin.get();
    
        using namespace Beispiel2;
    
        Ping p1;
        Pong p2;
        
        
        // Starte Threads ...
        // Obwohl der Ping-Thread vor dem Pong-Thread gestartet
        // wird ist AUF KEINEN FALL garantiert, dass er auch 
        // vor dem Pong-Thread läuft.
        p1.run();
        p2.run();
    
        p1.join();
        p2.join();
    }
    
    /*****************************************************************************/
    
    // PingPong Beispiel mit Condition Variablen
    //
    // In diesem Beispiel werden Condition Variablen um zwischen den
    // beiden Threads zu kommunizieren. Jeder Thread hat eine eigene 
    // Conditionvariable um dem Partner zu zeigen, dass er "den Ball
    // gespielt hat".
    // Da die Klasse PCondition keinen Copy-Konstruktor hat, werden die
    // zwei Variablen auf dem Heap angelegt und nur ein Zeiger über
    // die TSProxy Objekte allokiert. 
    // Da die PCondition Klasse selbst thread-safe ist, muss der 
    // Zugriff auf die PCondition Variable nicht extra synchronisiert
    // werden. Das heißt es kann NoLockPointer anstelle von LockPointer
    // benutzt werden.
    
    namespace Beispiel3
    {
        const string PING_COND = "PingCondition";
        const string PONG_COND = "PongCondition";
    
        class Ping : public PThread
        {
            void threadImpl()
            {
                // wenn diese Proxies angelegt werden, wurden die Zeiger
                // auf die Condition Variablen bereits im TSAllocator
                // angelegt (main). Diese Proxies erzeugen also nur Referenzen.
                TSProxy<string, PCondition*> pingCondition(PING_COND);
                TSProxy<string, PCondition*> pongCondition(PONG_COND);
    
                for(int i = 0; i < 10; ++i)
                {
                    // Hier muss nicht extra synchronisiert werden, da
                    // PCondition bereits von sich aus synchronisiert.
                    (*NoLockPointer<PCondition*>(pingCondition))->wait();
                    cout << "Ping 0" << endl;
                    (*NoLockPointer<PCondition*>(pongCondition))->signal();             
                }
            }
        };
    
        class Pong : public PThread
        {
            void threadImpl()
            {
                TSProxy<string, PCondition*> pingCondition(PING_COND);
                TSProxy<string, PCondition*> pongCondition(PONG_COND);
    
                for(int i = 0; i < 10; ++i)
                {
                    (*NoLockPointer<PCondition*>(pongCondition))->wait();
                    cout << "Pong 1" << endl;
                    (*NoLockPointer<PCondition*>(pingCondition))->signal();             
                }
            }
        };
    }
    
    void beispiel3()
    {
        cout << "Ping Pong Beispiel mit Condition Variablen. ";
        cout << "Press enter to start" << endl;
        cin.get();
    
        using namespace Beispiel3;
    
        // erzeuge zwei Condition Variablen auf dem Heap
        // SmrtPtr ist ein einfachen managed pointer
        // ähnlich dem std::auto_ptr
        SmartPtr<PCondition> pingCond(new PCondition);
        SmartPtr<PCondition> pongCond(new PCondition);
        // erzeuge die Zeiger auf die PCondition Objekte im 
        // Allocator.
        TSProxy<string, PCondition*> pingCondition(PING_COND, pingCond.get());
        TSProxy<string, PCondition*> pongCondition(PONG_COND, pongCond.get());
        
        // Setze die Condition Variable für den Ping Thread auf signalisiert.
        // Dieser Schritt ist notwendig, damit kein Deadlock entsteht,
        // da PConditions nach ihrer Erzeugung nicht signalisiert sind.
        // Würde dieser Aufruf weggelassen, würden beide Threads, Ping
        // und Pong auf das signalisieren ihrer Condition warten. Ein
        // Deadlock wäre die Folge.
        (*NoLockPointer<PCondition*>(pingCondition))->signal();
    
        
        Ping p1;
        Pong p2;
        
        
        // Starte Threads
        // Der Ping Thread (p1) wird zuerst laufen, da die Condition Variable pingCondition
        // auf "signalisiert" gesetzt wurde 
        p2.run();
        p1.run();
    
        p1.join();
        p2.join();
    }
    
    
    
    /*****************************************************************************/
    
    // Producer/Consumer Beispiel
    //
    // Ein Thread (Producer) erzeugt eine Reihe von Items, die von 
    // anderen Threads, den Constumern verarbeitet werden. Die 
    // Schwierigkeiten bei diesem Beispiel sind natürlich die Synchronisation
    // des verwendeten Puffers in dem die produzierten Items gespeichert werden
    // bevor sie konsumiert werden. Der Puffer (hier ein std::list) kann nur
    // eine bestimmte Anzahl von Elementen aufnehmen. Das bedeutet, das der 
    // Producer unterbrochen werden muss, wenn alle Speicherplätze im Puffer
    // belegt sind, so dass die Consumer arbeiten können.
    // Der Producer erzeugt insgesamt 10 Items. Jeweils fünf davon werden von
    // jedem Consumer Thread verarbeitet. Die Consumer müssen auf den Producer 
    // warten, falls keine Items im Puffer enthalten sind.
    
    namespace Beispiel4
    {
        const string BUFFER = "Bufferme";
    
        // der Typ des Puffers
        typedef list<int> BufferType;
    
        class Producer : public PThread
        {
            // Bestimmt wie viele Items maximal im Puffer gespeichert
            // werden dürfen. Bei einem STL Container ist das sicherlich
            // eine künstliche Einschränkung, bei einem Array jedoch 
            // nicht.
            unsigned maxItemsInQueue_;
    
            // In dieser Methode versucht der Producer ein Item zu pro-
            // duzieren und in dem Puffer zu speichern. Es gelingt im
            // falls noch nicht maxItemsInQueue_ im Puffer enhalten sind.
            bool try_produce(TSProxy<string, BufferType>& buffer, int& produced)
            {
                // Sperre Puffer für alle anderen Threads
                LockPointer<BufferType> BufferPtr(buffer);
                // teste ob noch Items produziert werden können
                if(BufferPtr->size() < maxItemsInQueue_)
                {
                    cout << "Producing item " << produced << endl;
                    BufferPtr->push_back(produced);                 
                    ++produced;
                    return true;
                }
                else
                {
                    cout << "Buffer full" << endl;      
                }
                // Entsperre Puffer
                return false;
            }
            void threadImpl()       
            {
                // Referenzen auf Puffer holen
                TSProxy<string, BufferType> buffer(BUFFER);
                
                // zehn Items produzieren
                for(int produced = 0; produced < 10;)
                {
                    if(!try_produce(buffer, produced))
                        pt_milli_sleep(50);
                }
            }
        public:
            Producer(int maxItems)
                :   maxItemsInQueue_(maxItems)
            {}
        };
    
        class Consumer : public PThread
        {
            int ID;
    
            // Hier versucht ein Consumer ein Item zu verarbeiten. Sind
            // noch Items im Puffer gelingt es im, ansonsten tut er 
            // nichts.
            bool try_consume(TSProxy<string, BufferType>& buffer, int& itemsConsumed)
            {
                LockPointer<BufferType> BufferPtr(buffer);
                // wenn noch Items vorhanden sind, konsumiere ein Item
                if(!BufferPtr->empty())
                {
                    cout << "Consumer <" << ID << "> Consuming item " << BufferPtr->front() << endl;
                    BufferPtr->pop_front();
                    ++itemsConsumed;
                    return true;
                }
                else
                {
                    cout << "Consumer <" << ID << "> No items to consume" << endl;
                }
                return false;
            }
            void threadImpl()
            {
                // Referenz anlegen
                TSProxy<string, BufferType> buffer(BUFFER);
                
                for(int itemsConsumed = 0; itemsConsumed < 5;)
                {
                    // versuche Item zu konsumieren
                    if(!try_consume(buffer, itemsConsumed))
                        pt_milli_sleep(50);             
                }
            }
        public:
            Consumer(int x) : ID(x) {}
        };
    }
    
    
    void beispiel4()
    {
        cout << "Producer-Consumer Beispiel mit einer std::list als Puffer. ";
        cout << "Press enter to start" << endl;
        cin.get();
        
        using namespace Beispiel4;
    
        Producer p(2);
        Consumer c1(1);
        Consumer c2(2);
    
        // starte Threads ...
        c1.run();
        p.run();
        c2.run();
    
        c1.join();
        c2.join();
        p.join();
    }
    
    
    /*****************************************************************************/
    
    // Ein weiteres Producer Consumer Beispiel. In diesem
    // Beispiel werden PMessageQueues benutzt um die Consumer
    // über das Erzeugen neuer Items zu informieren.
    // Hier gibt es keine maximale Anzahl von Items, die
    // erzeugt werden können. Jeder Consumer Thread wird 
    // über eine eigene PMessageQueue mit Items versorgt,
    // die er bearbeiten soll.
    
    namespace Beispiel5
    {
        const string MQ1 = "MessageQueue1";
        const string MQ2 = "MessageQueue2";
        
        // Typ der MessageQueue
        typedef PMessageQueue<int> IQueue;
    
    
        class Producer : public PThread
        {
            void threadImpl()
            {
                
                // der Consumer braucht Referenzen auf die PMessageQueues
                // aller Consumer, in diesem Fall 2
                // Hier werden wieder nur Referenzen auf die Queues
                // geholt, die PMessageQueues werden in main allokiert
                TSProxy<string, SharedPtr<IQueue> > Queue0(MQ1);
                TSProxy<string, SharedPtr<IQueue> > Queue1(MQ2);
                
    
                // erzeuge Items und stecke sie in die jeweilige Queue
                cout << "[Producer] producing 10 items" << endl;
                for(int i = 0; i < 10; ++i)
                {
                    
                    // erzeuge Zufallszahl zwischen 0 - 100
    
                    srand(static_cast<unsigned>(time(0)));
                    int z = rand();
                    if(z < 0) z *= -1;
                    z %= 100;               
    
                    cout << "Producing item " << z << endl;
                    
                    // wenn die Zahl kleiner als 50 ist dann bekommt sie 
                    // der erste Consumer, ansonsten der zweite.
                    if(z < 50)
                        // Da die PMessageQueue von sich aus den Zugriff thread-safe
                        // reguliert, reicht hier ein NoLockPointer
                        (*NoLockPointer< SharedPtr<IQueue> >(Queue0))->pushBack(z);
                    else
                        (*NoLockPointer< SharedPtr<IQueue> >(Queue1))->pushBack(z);
                    
                    // Warte eine Viertelsekunde (bessere Zufallszahlen)
                    pt_milli_sleep(100);
                }           
            }
        };
    
        class Consumer : public PThread
        {
            int ID;
            bool Keeprunning;
            void threadImpl()
            {
                // Die Consumer brauchen nur eine Referenz auf "ihre" PMessageQueue
                TSProxy<string, SharedPtr<IQueue> > Queue(ID == 1 ? MQ1 : MQ2);         
    
                while(Keeprunning)
                {
    
                    // wenn noch Items vorhanden sind, konsumiere ein Item
                    int Next = -1;
                    // versuche ein Item aus der Queue zu holen. Ist noch ein 
                    // Item vorhanden, gibt popFront() true zurück und der
                    // Variable Next wurde der Wert des ersten Items aus der 
                    // Queue zugewiesen.
                    if((*NoLockPointer< SharedPtr<IQueue> >(Queue))->popFront(Next))
                    {
                        cout << "Consumer <" << ID << "> Consuming item " << Next << endl;
                    }
                    else
                    {
                        // Kein Item in der Queue. Warte auf Nachricht
                        (*NoLockPointer< SharedPtr<IQueue> >(Queue))->waitForMessage();
                    }
                }
            }
        public:
            Consumer(int x) : ID(x), Keeprunning(true) {}
            void Quit() 
            { 
                Keeprunning = false; 
                // entsperre den Consumer Thread falls dieser auf einen Nachricht
                // wartet
                TSProxy<string, SharedPtr<IQueue> > Queue(ID == 1 ? MQ1 : MQ2); 
                (*NoLockPointer< SharedPtr<IQueue> >(Queue))->pushBack(0);
                
            }
        };
    }
    
    
    void beispiel5()
    {
        cout << "Producer-Consumer Beispiel mit einer PMessageQueue pro Consumer. ";
        cout << "Press enter to start" << endl;
        cin.get();
    
        using namespace Beispiel5;
    
        // Allokiere zwei PMessageQueues für die zwei Consumer
        // Da PMessageQueue keinen Copy-Konstruktor besitzt, muss
        // die Queue auf dem Heap erzeugt werden.
        TSProxy<string, SharedPtr<IQueue> > Queue0(MQ1, new IQueue);
        TSProxy<string, SharedPtr<IQueue> > Queue1(MQ2, new IQueue);
    
        Producer p;
        Consumer c1(1);
        Consumer c2(2);
        
        // Starte beide Consumer und den Producer.
        // Da zu Beginn noch keine Items in der Queue
        // enthalten sind, werden beide Consumer VERMUTLICH
        // warten müssen. Das ist aber nur der Fall, wenn
        // sie auch beide vor dem Producer laufen!!!
        c1.run();
        c2.run();
        p.run();
    
        p.join();
        
        c1.Quit();
        c2.Quit();
        c1.join();
        c2.join();
    }
    
    /*****************************************************************************/
    
    // Ein Beispiel für die Benutzung des ThreadPools
    // In diese Beispiel geht es darum eine ThreadPool zu erzeugen und anschließend
    // Requests zu erzeugen, welche die "docXXX.txt" Dateien aus diesem
    // Verzeichnis in das Verzeichnis copy kopieren
    // Die Requests werden von den Threads asynchron abgearbeitet, d.h. es herrscht
    // keine zeitliche Korrelation zwischen der Rückkehr der process()-Methode 
    // und der eigentlichen Bearbeitung durch den einen Thread. Der Request wird
    // lediglich zur Bearbeitung kopiert und dann ein Thread gescheduled. Wann dieser
    // Thread jedoch läuft, ist nicht vorherzusagen.
    
    
    namespace beispiel_6
    {
        // Definition des Requests
        // Eine KOPIE dieser Struktor oder Klasse wird an den Funktor
        // übergeben. Die Struktur muss den Request eindeutig beschreiben.
        // In unseren Fall wollen wir einen Datei kopieren, d.h. es 
        // reicht aus die Quell- und die Zieldatei zu kennen.
        struct Request
        {
            string from_;
            string to_;
            Request(const string& from, const string& to)
                :   from_(from)
                ,   to_(to)
            {}
        };
    
        // Definition des Funktors
        // Dieser Funktor wird von den Threads des ThreadPools 
        // pro Request ausgeführt. Als Parameter bekommt er 
        // eine KOPIE des Requests (die Signator des Funktors 
        // erwartet const Reference, um zu verhindern, dass die
        // Struktur ein drittes mal kopiert wird).
        struct CopyOneFile
        {
            void operator()(const Request& req)
            {
                // öffne die Quelldatei ...
                ifstream in(req.from_.c_str(), ios::binary);
                if(!in)
                {
                    // ... schade, hat nicht geklappt
                    cerr << "Could not open source file " << req.from_ << endl;
                    return;
                }
                
                // öffne und erstelle die Zieldatei ...
                ofstream out(req.to_.c_str(), ios::binary | ios::trunc);
                if(!out)
                {
                    // ... schade, hat nicht geklappt
                    cerr << "Could not create copy " << req.to_ << endl;
                    return;
                }
    
                // öffne und erstelle die Zieldatei ...
                cout << "Copying file " << req.from_ << " to " << req.to_ << endl;
                out << in.rdbuf();
            }
        };
    }
    
    void beispiel6()
    {
        cout << "Mehrere Dateien mit einen Threadpool kopieren. ";
        cout << "Press enter to start" << endl;
        cin.get();
        
        using namespace beispiel_6;
        
        // erzeuge einen Threadpool mit 3 Threads
        PThreadPool<CopyOneFile, Request> pool(3);
        char from[100];
        char to[100];
        // kopiere 10 Dateien
        for(int i = 1; i <= 10; ++i)
        {
            // erzeuge Quell- und Zieldateinamen
            sprintf(from, "../original/doc%d.txt", i);
            sprintf(to, "../copy/doc%d.txt", i);
    
            // veranlasse Requestverarbeitung
            pool.process(new Request(from, to));
            cout << "Busy: " << pool.active() << ", size: " << pool.size() << endl;
        }
    }
    
    /*****************************************************************************/
    
    // In diesem Beispiel werden zwei Producer und zwei Consumer über eine 
    // sogenannte "lock-free" Queue synchronisiert. Im Gegensatz zur PMessageQueue
    // muss die Datenstruktur nicht "gelockt" werden. Dies bringt einen entscheidenden
    // Geschwindigkeitsvorteil, das das sperren über Mutexe einen (für Rechnerverhältnisse)
    // recht zeitraubende Aktivität ist. Zudem können gleichzeitig mehrere Threads in die
    // Queue schreiben bzw. aus der Queue lesen.
    // In diesem Beispiel werden nackte Pointer auf Heap-Speicher in die Queue gesteckt. In
    // einen richtigen Programm sollte man an dieser Stelle Smartpointer verwenden.
    
    namespace beispiel_7
    {
        // Queue
        typedef PLockFreeQueue<int*> Buffer;
        
        class Producer : public PThread
        {
        public:
            Producer(int id, Buffer& buffer, int runs, int add)
                :   id_(id)
                ,   runs_(runs)
                ,   buffer_(buffer)
                ,   add_(add)
            {}
        private:
            void threadImpl()
            {
                for(int i = 0; i < runs_; ++i)
                {
                    const int idToProduce = i+add_;
                    // Produziere ein "Item" und füge es in die Queue ein...
                    buffer_.pushBack(new int(idToProduce));
                    printf("%d producing item %d\n", id_, idToProduce);
    
                    pt_milli_sleep(50);
                }
            }
        private:
            const int id_, runs_;
            Buffer& buffer_;
            int add_;
        };
    
        class Consumer : public PThread
        {
        public:
            Consumer(int id, Buffer& buffer, int runs)
                :   id_(id)
                ,   buffer_(buffer)
                ,   runs_(runs)
            {}
        private:
            void threadImpl()
            {
                for(int i = 0; i < runs_;)
                {
                    int* item = 0;
    
                    // Versuche ein Item aus der Queue zu nehmen.
                    // Schlägt fehl, falls die Queue leer ist.
                    if(buffer_.popFront(item))
                    {
                        assert(item);
                        printf("%d consuming item %d\n", id_, *item);
                        delete item;
                        ++i;
                    }
                    else
                    {
                        printf("%d empty\n", id_);
                        pt_milli_sleep(50);
                    }
                }
            }
        private:
            const int id_;
            Buffer& buffer_;
            const int runs_;
        };
    }
    
    void beispiel7()
    {
        cout << "Producer-Consumer Beispiel mit 2 Producern und 2 Consumern. Die Threads schreiben in/lesen aus einer lock-free Queue. ";
        cout << "Press enter to start" << endl;
        cin.get();
    
        using namespace beispiel_7;
    
        Buffer buffer;
        // Producer 1 erzeugt 20 Items mit Id 0 aufwärts
        Producer producer1(1, buffer, 20, 0);
        // Producer 2 erzeugt 20 Items mit Id 20 aufwärts
        Producer producer2(2, buffer, 20, 20);
    
        // Consumer 1 und 2 verbrauchen je 20 Items
        Consumer consumer1(1, buffer, 20);
        Consumer consumer2(2, buffer, 20);
    
        consumer1.run();
        consumer2.run();
        producer1.run();
        producer2.run();
    
        producer1.join();
        producer2.join();
        consumer1.join();
        consumer2.join();
    }
    
    
    
    /*****************************************************************************/
    
    // Eine Barrier ist nützlich um Threads an einer bestimmten Stelle im Code so lange
    // zu blockieren, bis einen gewisse Anzahl die Stelle erreicht hat. Dies kann zum 
    // Beispiel nützlich sein um das sequentiellen Starten von Threads von derem 
    // "Arbeitsbeginn" zu entkoppeln.
    
    
    namespace beispiel_9
    {
        class WaitAtBarrier : public PThread
        {
        public:
            WaitAtBarrier(int id, PBarrier& barrier)
                :   id_(id)
                ,   barrier_(barrier)
            {}
            void threadImpl()
            {
                cout << "Thread " << id_ << " waiting at barrier" << endl;
                barrier_.wait();
                cout << "done\n";
            }
        private:
            const int id_;
            PBarrier& barrier_;
        };
    }
    
    void beispiel9()
    {
        cout << "Barrier-Beispiel. Es wird eine Barriere für 5 Threads erzeugt und anschließend\n";
        cout << "fünf Threads. Der letzte Thread entsperrt dabei die Barriere und alle 5 Threads\n";
        cout << "können losrechnen. ";
        cout << "Press enter to start" << endl;
        cin.get();
    
        using namespace beispiel_9;
    
        // Erzeuge Barriere an der 5 Threads
        // warten können.
        PBarrier barrier(5);
    
        
        WaitAtBarrier w1(1, barrier), w2(2, barrier), w3(3, barrier), w4(4, barrier), w5(5, barrier);
        
        // Erzeuge nacheinander die Threads. Die
        // ersten vier werden an der Barriere geblockt...
        w1.run();
        w2.run();
        w3.run();
        w4.run();
        cout << "Now four threads are waiting at the barrier.\n";
        cout << "Press enter to start the fifth thread that will unlock the barrier.\n";
        cin.get();
        w5.run();
    
        // ...der 5. Thread entsperrt die Barriere wenn er  
        // PBarrier::wait aufruft. Die Barrier kehrt in 
        // ihren Ausgangszustand zurück.
        cout << "Threads done waiting at barrier!\n";
    
        w1.join();
        cout << "Thread 1 joined!" << endl;
        w2.join();
        cout << "Thread 2 joined!" << endl;
        w3.join();
        cout << "Thread 3 joined!" << endl;
        w4.join();
        cout << "Thread 4 joined!" << endl;
        w5.join();
        cout << "Thread 5 joined!" << endl;
    }
    
    
    /*****************************************************************************/
    
    // Dieses Beispiel demonstriert die class PTime (Zeitmessung) und PRandom 
    // (pseudo Zufallszahlen). 
    // PTime stellt akkurate Messergebnisse bis in dem Mikrosekunden-Bereich bereit und
    // ist direkt als Stopuhr einsetzbar.
    // PRandom ist eine Implementation der Mersenne Twister 32 Bit Zufallszahlen von
    // Makoto Matsumoto und Takuji Nishimura. Sie sind ein sicherer Ersatz für die 
    // standard rand() fund srand() Funktionen, da sie als Klasse gekapselt sind
    // und daher nicht synchronisiert werden müssen. Der gleichzeitige Zugriff auf 
    // ein und das selbe PRandom Objekt muss allerdings nach wie vor synchronsisiert
    // werden, zwei verschiedene Objekte sind aber unabhängig.
    
    namespace beispiel_10
    {
    
        class GenerateNumbers : public PThread
        {
        public:
            GenerateNumbers(int id, unsigned long seed)
                :   id_(id)
                ,   random_(seed)
            {}
        private:
            void threadImpl()
            {
                cout << id_ << " " << "Start generating random numbers" << endl;
                stopwatch_.start();
                for(int i = 0; i < 20; ++i)
                    cout << id_ << " Nr. " << i << ": " << random_.rand() << endl;
                stopwatch_.stop();
                cout << id_ << " " << "Stop generating" << endl;
                cout << id_ << " " << "Time in seconds: " << (double)(stopwatch_.difference()*1.0)/(stopwatch_.frequency()*1.0) << endl;
                cout << id_ << " " << "Frequency: " << stopwatch_.frequency() << endl;
    
                cout << id_ << " " << "Timestamp: " << (unsigned) stopwatch_.stamp() << endl;
            }
        private:
            const int id_;
            PTime stopwatch_;
            PRandom random_;
        };
    }
    
    void beispiel10()
    {
        cout << "Generieren von Zufallszahlen in mehreren Threads. Beide Threads generieren\n";
        cout << "exakt die selben Zufallszahlen. ";
        cout << "Press enter to start" << endl;
        cin.get();
    
        using namespace beispiel_10;
    
        const unsigned long seed = (unsigned long)time(0);
        GenerateNumbers g1(1, seed), g2(2, seed);
    
        g1.run();
        g2.run();
    
        g1.join();
        g2.join();
    }
    
    namespace beispiel_11
    {
        class SelfDeleter : public PThread
        {
        private:
            void threadImpl()
            {
                cout << "Thread: waiting  to be unblocked..." << endl;
                pt_second_sleep(1);
                cout << "Thread: deleting myself now, still joinable!" << endl;
                delete this;
            }
        };
    }
    
    void beispiel11()
    {
        using namespace beispiel_11;
    
        cout << "\n-> Joining on a thread that deletes himself. Press enter to start.\n" << endl;
        cin.get();
        SelfDeleter* sd = new SelfDeleter();
    
        cout << "Main: starting thread..." << endl;
        sd->run();
        cout << "Main: joining thread" << endl;
        // NOTE: join MUST be called before the thread executes
        // his delete this statement.  Otherwise a method is
        // called on invalid memory!
        sd->join();
    }
    
    void beispiel12()
    {
        using namespace beispiel_11;
    
        cout << "\n-> Trying multiple runs on a thread that deletes himself. Press enter to start.\n" << endl;
        cin.get();
        SelfDeleter* sd = new SelfDeleter();
    
        cout << "Main: starting thread..." << endl;
        int ret = sd->run();
        assert(ret == 0);
        ret = sd->run();
        assert(ret < 0);
        cout << "Main: joining thread" << endl;
        // NOTE: join MUST be called before the thread executes
        // his delete this statement.  Otherwise a method is
        // called on invalid memory!
        sd->join();
    }
    
    namespace beispiel_13
    {
        class DeadlockAttempt : public PThread
        {
            void threadImpl()
            {
    #ifndef WIN32
                cout << "deadlock thread: " << pthread_self() << endl;
    #endif
                cout << "Thread: Attempting to join myself, effectively trying to deadlock..." << endl;
                const int ret = join();
                assert(ret == PT_THREAD_DEADLOCK);
                cout << "Thread: join failed (good!)" << endl;
            }
        };
    }
    
    void beispiel13()
    {
        using namespace beispiel_13;
    
        cout << "\n-> No thread can join itself. Press enter to start.\n" << endl;
        cin.get();
        
    #ifndef WIN32
        cout << "main thread: " << pthread_self() << endl;
    #endif
        DeadlockAttempt da;
        da.run();
        
        int ret = da.join();
        assert(ret != PT_THREAD_DEADLOCK);
    
    }
    #if 0
    void beispiel14()
    {
        using namespace beispiel_13;
    
        cout << "\n-> Join via dtor\n" << endl;
        cin.get();
        
    #ifndef WIN32
        cout << "main thread: " << pthread_self() << endl;
    #endif
        DeadlockAttempt da;
        da.run();
        
    }
    #endif
    
    
    int main()
    {
    #ifdef _MSC_VER
        if(1)
        {
            _CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) |
                        _CRTDBG_LEAK_CHECK_DF | _CRTDBG_ALLOC_MEM_DF |
            _CRTDBG_CHECK_ALWAYS_DF);
            _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
            _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
            _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
            _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR );
            _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
            _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );
        }
    #endif
        
        beispiel1();
        beispiel1_1();  
        beispiel2();
        beispiel3();
        beispiel4();    
        beispiel5();
        beispiel6();
        beispiel7();
        
        beispiel9();
        
        beispiel10();
    
        beispiel11();
        beispiel12();
        
    
        beispiel13();
        
        
        printf("main end\n");
        return 0;
    }