RTSYST Opdracht 3: Multi-threaded programmeren in C++11.

© Harry Broeders.

C++11.

Bij deze practicumopgave maken we gebruik van de C++11 standaard library. Je mag daarbij gebruik maken van gcc versie 4.7 of hoger maar ik ga er in deze omschrijving vanuit dat je gebruik maakt van Microsoft Visual C++ 2013 Express Edition. Deze ontwikkelomgeving is in lokaal D1.049 en ook in lokaal D1.052 geïnstalleerd.

Opdracht 3a.

Test het in de theorie behandelde programma main.cpp. Voeg nu nog een thread toe aan dit programma. Deze thread moet 40x telkens na 5 ms de boodschap "Hallo" op het scherm zetten en de cursor op het begin van de volgende regel zetten. Pas het programma zodanig aan dat alle 3 de threads dezelfde code (functie) gebruiken.

Multi-threaded circular buffer.  

Het probleem dat we (opnieuw) gaan analyseren is het zogenaamde producer-consumer synchronisatie probleem.

Het voorbeeld programma bestaat uit 3 threads: 2 producers en 1 consumer. De producers produceren data en zetten dit in een buffer. De consumer leest de data uit de buffer en consumeert deze data. Vanzelfsprekend moet ervoor gezorgd worden dat producers en consumer synchroniseren:

In C++ kun je alle data en functies van de buffer "inkapselen" in de class CircularBuffer. Door een template te gebruiken kunnen we een herbuikbaar buffer definiëren dat met elk willekeurig type gebruikt kan worden. Ook het aantal plaatsen in de buffer kunnen we met behulp van een template parameter instelbaar maken.

template<typename T, int size>
class CircularBuffer {
public:
    CircularBuffer();
    void put(const T& t);  // schrijf element  in de buffer. WACHT als buffer vol is!
    const T get();         // lees een element uit de buffer. WACHT als buffer leeg is!
    bool isEmpty() const;  // vraag of het buffer leeg is
private:
//  Nog invullen!
};

Het multi-threaded testprogramma voor de class CircularBuffer kun je vinden in de file main.cpp.

Opdracht 3b.

Implementeer de class CircularBuffer met behulp van de C++11 library. Bedenk goed hoe je kunt zien dat jou implementatie correct werkt! Is de uitvoer voorspelbaar?

De code van de consumer lijkt inefficient:

    for (int i = 0; i < 1000; ++i) {
        char c = b.get();
        {
            unique_lock<mutex> lock(m_cout);
            cout << c;
        }
    }

Het gebruik van de lokale variabele c lijkt overbodig.

    for (int i = 0; i < 1000; ++i) {
        unique_lock<mutex> lock(m_cout);
        cout << b.get();
    }

Opdracht 3c.

Wat is de uitvoer als de lokale variable c in de consumer wordt verwijderd (zoals hierboven gegeven)? Verklaar dit.

Verder met opdracht 4...