YANE-Framework Tutorial 1.1.0

Tutorial page of the Class yane::Utils::Thread

This demo shows the use of Threads in combination with Mutex. In this example the sum from 0 to maxiter is calculated. The threads operate on one shared variable (therefore we need a Mutex) and calculate the sum together.

Threads

Common in both examples is the use of threads. We use the threads class to create Threads. Usually a thread is used as following:

Introduction

Apart from the methods explained above, we need to initialize the computation to set the pointers to the Mutex, sum and iteration variable. If the run() function is called every thread wants to lock the Mutex. One thread is successful, the other threads are waiting until the first one has finished. The first thread computes and unlocks the Mutex after the computation is finished. After that every thread trys to lock ... and so on.
Remark: Without a Mutex it is possible to loose data.

Libraries

The first thing to do is to define the libraries which we require. These libraries form the head of our main program:

#include <iostream>
#include <cstdlib>

#include <yane/utils.h>

#include "computationthread.h"

Namespaces

Having defined the libraries which we are going to use, we now have to define the namespaces in which the classes of these libraries operate:

using namespace yane::Utils;
using namespace std;

Main Program

First we need to create a thread_array and a debugmaster. Next, we declare and initialize some variables which we are going to use. Here we also create the Mutex which will be used by the threads.

int main ()
{
        int threads = 3;
        ComputationThread * thread_array[threads];

        yane::Utils::RTClock * clock = new yane::Utils::RTClock();
        yane::Utils::DebugMasterConsole * dm = new yane::Utils::DebugMasterConsole ( clock, 90 );
        yane::Utils::DebugClient * debug_client = dm->newClient ( "Main" );
        dm->setLevel ( 6 );

        int sum = 0, tmp;
        int iter = 0;
        yane::Utils::Mutex * mutex = new yane::Utils::Mutex();

Now we create a thread object named "Thread1", and so on. The last three parameters are pointers to the Mutex and variables we are using for the computation.

        for ( ... )
                ostringstream oss;
                oss << "Thread" << i;
                thread_array[i] = new ComputationThread ( oss.str(), dm , mutex, &sum, &iter);

After the object is created we need to start the thread. Until now only a thread object existed, with start we actually create the thread.

        for ( ... )
                thread_array[i]->start();

The threads are working now and we don't know when they are finished. Hence, we tell the main program to wait for the theads, i.e. the main program is blocked until all threads are finished.

        for ( .. )
                thread_array[i]->wait();

Once the computation is finished, we write the result to the debugmaster and delete all created objects.

        debug_client->sendDebugInfo ( "Threads finished.", "", 0, 0, 0, 3 );
        debug_client->sendDebugInfo ( "", "computed result: ", &sum, sizeof ( int ), DebugMaster::T_INT , 2 );

        for ( ... )
{
                delete thread_array[i];
}
        delete mutex;
        delete dm;
        delete debug_client;
        delete clock;

Tutorial page of the Class yane::Utils::Thread

We need to look at the run() function. The constructor saves the pointers to mutex, sum and iter. The run() function is called when a new thread is started. Once the run function is finished the thread closes itself. In the following code debug messages are written to the debug master and we initialize the sleep function. The loop is explained in the next step.

void yane::Utils::ComputationThread::run()
{
        debugMessage ( "Calculation started", 5 );

        srand ( time ( NULL ) );

        // loop

        debugMessage ( "Calculation finished", 5 );
}

The thread loop

We have a infinite loop (the infinite loop is not necessary here, but usually in threads you'll have infinite loops). In the loop the thread tries to lock the mutex, if unsuccessful it is blocked until the mutex is unlocked. Otherwise the thread checks whether the computation is finished, if not the computation is done and the mutex is unlocked. The computation is very fast and creating a thread is relatively slow, therefore we need to wait some time to actually get the threads competing against each other (without waiting, thread 0 finishes the computation before thread 1 is even started).

        while ( true )
{
                _mutex->lock();

                if ( *_iter > 10 )
{
                        _mutex->unlock();
                        break;
}

 *_sum = *_sum + *_iter;
 *_iter = *_iter + 1;

                _mutex->unlock();

                usleep ( 100 );
}