My C++ Learning Diary

Sunday, March 17, 2013

const volatile C++



An object marked as const volatile will not be allowed to change by the code where it is declared. The error will be raised due to the const qualifier. The volatile part of the qualifier means that the compiler cannot optimize the code with respect to the object.

In an embedded system this is typically used to access hardware registers that can be read and are updated by the hardware, so it makes no sense to be able to write to the register via the code. An example might be the status register of a serial port.Various bits will indicate a status like if a character is waiting to be read. Each read to this status register could result in a different value depending on what else has occurred in the serial port hardware. It makes no sense to write to the status register but you need to make sure that each  read of the register results in an actual read of the hardware.

Below is an illustration :

//We assume that the below declared pointers point to the correct
//hardware addresses
unsigned int const volatile *status_reg;
unsigned char const volatile *recv_reg;

#define CHAR_READ 0x01

int get_next_char()
{
 while((*status_reg & CHAR_READ) == 0);
 return *recv_reg;
}

Thursday, January 14, 2010

Templates


Custom Search


Wow... a new dimension in C++ coding ... Templates have taken re-usability to a new level , it is the reuse of source code. Yes that's what Template is all about, generic source code developement. Well you already must be knowing the basics , but just for the sake of completeness we will them and move on.

Defining a function template:
template<class T>
void swap(T &a , T &b)
{
   T tmp = a;
   a = b;
   b = tmp;
}

Using a template function:
 Its simple just call like a normal function.... 

int main()
{
  int a =10, b = 20;
  swap( a,b);
   ......
  char x = 'a' , y = 'b';
  swap(x,y);
  .....
}

Note the underlined terms used with respect to the context, in the above headings.

Defining Class Templates
templates<class T>
class X
{
private:
   T data;
public:
 X(T a)
{
   data = a;
}

T getData();
..... 
};

//defining the class template method
template<class T>
T  X<T>::getData()
{
  return data;
}

Using the template class

int main()
{
.....
 X<int> obj(10);
....
int a = obj.getData();
....
}.

As templates are not normal functions or classes they are not compiled until required(on instantiation with the appropriate arguments) we cannot separate the interface and the implementation into two (.h & .cpp)  files, they must be in the same file.



Template Instantiation

Template instantiation can be of two types Implicit(the compiler generates the code by itself because of the instantiation) and Explicit(the programmer tells the compiler to generate  the code). See the below examples:

// Consider the class template
template<class T>
class X
{
 private:
     T  data;
public:
    T getData();  // member function that uses the template type(here T).
};

// case 1
int main()
{
   X<int> xi;          //implicit instantiation generates class X<int>
   X<double> xd;  //implicit instantiation generates class X<double>
   xi.getData();               //generates function X<int>::getData()
   xd.getData();             //generates function X<double>::getData()
   return 0;

}


//case 2

int main()
{
   template class X<int>  // explicit instantiation of class X<int> , no object declared.

   return 0;
}

//case3
// This time the compiler does not declare any definition because there is no need.
// Its the same as declaring a pointer to an undefined class.
int main()
{
   X<int>  *p_xi;          //instantiation of class X<int> not required.
   return 0;
}

//case 4
// Implicit instantiation function template
template<class T>
T max(T a, T b)
{
  return (a>b)? a: b;
}

int main()
{
 int i;
 i  = max(10, 20) ;   // implicit instantiation of max(int ,int)
 return 0;
}

// case 5
// explicit instantiation of function templates.

template<class T>
T fun(T a)
{
 ....
}

int  main()
{
   template  int fun (int);  // explicit instantiation
    ... 
   return 0;

}

In an extern declaration of a template the compiler does not instantiate a class template or a function template.

The typename keyword
The type name keyword tells the compiler to interpret a particular name as a type.
Have a look at the below example:

#include <iostream>

using namespace std;

class Y
{
public:
 class ID
 {
     public:
      void g()
      {
          cout << "In Y::ID::g()" << endl;
      }
 };
};

template<class T>
class X
{
    typename T::ID id;  // if we did not use the typename keyword the compiler would have given an error.
    public:
    void fun()
    {
     id.g();
    }
};


int main()
{
    X<Y> xy; 
    xy.fun();
    return 0;


In the template definition we are making two assumptions , first that inside the class T there is an identifier 'ID' and second the identifier 'ID' is actually a nested type inside T. So while compiling X the compiler will not know that 'ID' is a type and we need to convey that to the compiler. We use the typename keyword to tell the compiler that 'ID' is a type ,  if we don't say that the compiler will give an error. So here is  a simple rule that if your type is a qualified name that involves a template argument the you must use the typename keyword.


With the introduction of the typename keyword you can use it in place of  class while declaring template argument list of a template definition.


Templates and multiple file implementation:

The code for a specific template is not generated by the compiler until an instantiation takes place. Because templates are compiled when required , this forces a restriction for multi-file implementation of templates, so the implementation of a template class or function must be in the same file. 


An interesting program: A template class to find the factorial of a number.

template<long N>


class Factorial
{
    public:
    long Value()
    { 
        return N * fn_1.Value();
    }
    
    private:
    Factorial<N-1> fn_1;
};


// Specilized for the value 0
template<>
class Factorial<0>
{
    public:
    long Value()
    {
      return 1;
     }
};


int main()
{
     Factorial<20> f20;
     cout << f20.Value() << endl;
}

Monday, January 11, 2010

Function Objects

In the world of C++ every thing changes.... in C we use a pointer to a function is used to implement callbacks.. C++ provides a far better alternative the function objects(functors). Function objects are simple classes that overload the () operator , so normally they behave like functions because they have overloaded the () operator but they are actually objects. Using function objects over function pointers gives us a lot of advantages like , the function objects may contain member variables that can be used to store the state of the object, they are more stable to changes as compared to function pointers , well you may say that the function pointers also support changes but you would need to keep the prototype same otherwise you break the existing stable code that uses the function pointer where as in the case of  function objects you can just another overloaded version of the () operator to the function object class. From optimization point of view you have the option of making the overloaded () operator as inline thus finally avoiding a function call if it is required. You also have the option of having a generic function object with the help of templates , we willsee them as we go along.

Now let us see how we can implement a function object.

class Minus
{
public:
    int operator()(int a, int b) const
    {
        return (b - a);
    }
};


Now let us use the fuction object.

int testFunctionObject(int a, int b, Minus &sub )
{
   return sub(a,b);

 

int main()
{
  Minus funObj;

  cout << testFunctionObject(10,20, funObj);
  return 0;



cool ha...
 The call to sub inside the testFunctionObject() is not a simple function call sub is an object and the statement sub(a,b) is transformed to sub.operator()(a,b) .

Now lets create a generic function object using templates.


template <class T>
class Add
{
public:
    T operator()(T a,T b) const
    {
        return (a+b);
    }
};


or we can also implement in another way

class Mul
{
public:
    template
<class T> T operator()(T a,T b) const {return a*b;}
};


The standard library defines several useful function objects that are used in STL algorithms for example in the sort() algorithm takes a predicate object as its third argument.... now what is predicate object , well it is a template function object that returns a bool result (greater<> / less<> used in sort to set the sorting order to ascending or descending). See the example below:

int main()
{
 vector vi;

 //..fill vector
 sort(vi.begin(), vi.end(), greater<int>() );
//descending
 sort(vi.begin(), vi.end(), less
<int>() ); //ascending




A full example of function object use can be found below:
 

#include <iostream>

using namespace std;

//Normal function objects
class Minus
{
public:
    int operator()(int a, int b) const
    {
        return (b - a);
    }
};



//Generic function objects

template <class T>
class Add
{
public:
    T operator()(T a,T b) const
    {
        return (a+b);
    }
};


//Another way of defining generic function objects this is much simpler to use see the main() function
class Mul
{
public:
    template
<class T> T operator()(T a,T b) const {return a*b;}
};


//Using function pointers.

double Div(int a , int b)
{
    double c = 0.00;
    if(b!=0)
    {
        c = a/b;
    }
    return c;
}



int main()
{
    int a=10,b = 30,c;
    Minus sub;
    c=sub(a,b);
    cout << c << endl;


    Add<double> dblAdd;
    cout << dblAdd(2.456,5.789) << endl;
    Add
<int> intAdd;
    cout << intAdd(4,6) << endl;


    Mul mul;
    cout << mul(4.897,7.0) << endl;


    double (*fptrDiv)(int,int); 
// defining the function pointer
    fptrDiv = &Div;
    cout << fptrDiv(20,10) << endl;


    return 0;





.

Friday, January 8, 2010

Multithreading Basics

Process : In computing, a process is an instance of a computer program, consisting of one or more threads, that is being sequentially executed by a computer system.

Thread : A thread is defined as an independent stream of instructions that can be scheduled to run by the operating system. Threads are popular way to improve application through parallelism. The CPU switches rapidly back and forth among the threads giving illusion that the threads are running in parallel. Each thread has its own stack. Since thread will generally call different procedures and thus a different execution history. This is why thread needs its own stack.A thread has its own program counter (PC), register set, and a stack space. Threads are not independent of one other like processes as a result threads shares with other threads their code section, data section, OS resources such as open files and signals.


User Level Threads: They do not interact with the Kernal for their creation , they are created by user level libraries , the kernel does not see them as a separate threads and doesn't schedule them for execution it is all internal to the process the threads belong to. The advantages of these threads are their context switching are fast, and they can be implemented on an OS that doesn't support multithreading , The disadvantage is that if a thread gets blocked the whole process is blocked.



Kernel Level Threads: These threads are created and managed by system calls to the OS kernel. The Kernel maintains a thread table and are responsible for their scheduling.  The advantage of kernel level threads are that if a thread blocks the whole process is not blocked because the other threads belonging to the process are still running. And the disadvantage of this is that they are comparatively slower than user level threads.


Starvation : This term specifies that when a process is waiting for a resource to complete but never receives that resource. Starvation leads to deadlock and livelock(which is a special case when the processes keeps changing their state).

Deadlock : When two or more process are waiting for each other to release a resource or when more than two processes are waiting for resources held by each other in a circular chain. For example think that there are two process are running (ProcessA and ProcessB) and there are two resources (ResourceX and ResourceY), now ProcessA is holding ResourceX and to complete it requires ResourceY and ProcessB is holding ResourceY and to complete it requires ResourceX , so both the process are waiting for each other for the resource it requires to complete and as a result none of them complete , this is a deadlock.

A real life example is suppose two person are drawing lines on pages and there is one pencil and one ruler , now one of the person takes the pencil and is waiting for the ruler to draw the line whereas on the other hand the other person has the ruler and is waiting for the pencil.


Livelock: It is similar to a deadlock and occurs when two or more processes continually change their state in response to changes in the other processes. A real-world example of livelock occurs when two people meet in a narrow corridor, and each tries to be polite by moving aside to let the other pass, but they end up swaying from side to side without making any progress because they both repeatedly move the same way at the same time.

 
Priority Inversion: When a high priority process is waiting for a resource that is held by a low priority process.

Race Condition: When two or more threads or processes are simultaneously trying to update a shared resource the final state of the resource is unpredictable. For example, let us assume that two threads T1 & T2 are trying to update the value of a global integer by 1. From our perspective the following sequence of steps should take place.

1. Int i = 0 (value in memory).
2. T1 reads the value of i from memory and loads it into the register1 (reg1 = 0).
3. T1 increments the value of reg1 to 1.
4. T1 sets the value of i in memory to reg1 (i = reg1) , so now the value of i in memory is 1.
5. T2 reads the value of i from memory and loads it into the register2 (reg2 = 1).
6. T2 increments the value of reg2 to 2.
7. T2 sets the value of i in memory to reg1 (i = reg2) , so now the value of i in memory is 2.
8. Int i = 2 (value in memory).


but as the sequence is unpredictable as both the threads run simultaneously, for example see the sequence below.


1. Int i = 0 (value in memory).
2. T1 reads the value of i from memory and loads it into the register1 (reg1 = 0).

3. T2 reads the value of i from memory and loads it into the register2 (reg2 = 0).
4. T1 increments the value of reg1 to 1.
5. T2 increments the value of reg2 to 1.
6. T1 sets the value of i in memory to reg1 (i = reg1) , so now the value of i in memory is 1.
7. T2 sets the value of i in memory to reg1 (i = reg2) , so now the value of i in memory is 1.
8. Int i = 1 (value in memory).


we get the wrong value as the final outcome , this is due to race condition.


Critical Section:  A critical section is a piece of code that access a shared resource and must not be executed by more than thread at a time.


Semaphore : A semaphore restricts the number threads that can simultaneously access a shared resource.A binary semaphore is similar to mutex.

Mutex :  Mutex is an object that is used to synchronize access to a shared resource using locking and unlocking mechanisms.

Condition Variable : A condition variable is used to synchronize to execution of threads via the thread notification mechanism (wait & notify).


Followers

About Me