29
Nov
0

C++ – OpenMP – Private, share, copy, contructor, etc. examples

In this post I show quickly what does your program copy when you are using “share” or “private” clause with openMP.

The Code

The code contains, a custom class to print, a custom class to show actions on an object and several examples.

As you will see, we cannot specified scope property on the attributes of a class.

/**
* Berenger - 2010 - From http://Berenger.eu
* This example show the differences between sharing or not variables in openMP
*/

#include <sstream>
#include <omp.h>
#include <iostream>
#include <string>

////////////////////////////////////////
// To print
////////////////////////////////////////

/**
* This class is used to print only when we have a full line
* if we use std::cout << bla << bla, because there are several thread
* the line can be concatened!
*/
class Printer {
 std::ostringstream buffer;

public:
 Printer(){}

 Printer(const Printer& other) : buffer(other.buffer.str()){}

 enum Action{
 PRINT,
 };

 template <class T>
 Printer& append(const T& input){
 buffer << input;
 return *this;
 }

 Printer& append(const Action& input){
 switch(input){
 case PRINT :
 std::cout << buffer.str();
 buffer.clear();
 break;
 };
 return *this;
 }

 template <class T>
 Printer& operator<<(const T& input){
 return append(input);
 }

 static Printer Build(){
 return Printer();
 }
};

////////////////////////////////////////
// Test Object
////////////////////////////////////////

/**
* This object simply show construct, copy, destroy actions
*/
class MyObject{
private :
 // static counter
 static int Counter;
 // obj index
 int index;
 // the object name to find them more easily
 std::string name;

public :
 MyObject(const std::string& inName = std::string("No Name")) : name(inName){
 #pragma omp critical
 {
 index = Counter++;
 }
 Printer::Build() << "\t\t[" << name << "] Creator " << index << ", thread " << omp_get_thread_num() << "\n" << Printer::PRINT;
 }
 MyObject(const MyObject& obj){
 #pragma omp critical
 {
 index = Counter++;
 }
 name = "Copy of " + obj.name;
 Printer::Build() << "\t\t[" << name << "] Copy creator from " << obj.index << " to " << index << ", thread "<< omp_get_thread_num() << "\n" << Printer::PRINT;
 }
 MyObject& operator=(const MyObject& obj){
 Printer::Build() << "\t\t[" << name << "] Copy assignement from " << obj.index << " to " << index << ", thread "<< omp_get_thread_num() << "\n" << Printer::PRINT;
 return *this;
 }
 virtual ~MyObject(){
 Printer::Build() << "\t\t[" << name << "] Delete " << index << "\n" << Printer::PRINT;
 }

 void printid() const{
 Printer::Build() << "\t\t[" << name << "] I am " << index << ", thread " << omp_get_thread_num() << "\n" << Printer::PRINT;
 }

 int id() const{
 return index;
 }

 static void Reset(){
 Counter = 0;
 }
};

// Counter starts from 0
int MyObject::Counter = 0;

////////////////////////////////////////
// Tests function
////////////////////////////////////////

/* OUT ---------------------------
Enter TestShareObject
 [Original] Creator 0, thread 0
 [T]Thread 0 working
 [T]Thread 1 working
 [Original] I am 0, thread 0
 [Original] I am 0, thread 1
 [T]Thread 0 finished
 [T]Thread 1 finished
 [Original] Delete 0
Quit TestShareObject
----------------------------------*/
// Test with share clause (share is usualy = default)
void TestShareObject(){
 MyObject::Reset();
 Printer::Build() << "Enter TestShareObject" << "\n" << Printer::PRINT;
 {
 const double startTime = omp_get_wtime();
 MyObject obj("Original");

 #pragma omp parallel default(none) shared(obj)
 {
 Printer::Build() << "\t[T]Thread " << omp_get_thread_num() << " working\n" << Printer::PRINT;
 obj.printid();
 while( (omp_get_wtime() - startTime) < double(omp_get_thread_num()*1.0));
 Printer::Build() << "\t[T]Thread " << omp_get_thread_num() << " finished\n" << Printer::PRINT;
 }
 }
 Printer::Build() << "Quit TestShareObject" << "\n" << Printer::PRINT;
 Printer::Build() << "--------------------" << "\n" << Printer::PRINT;
}

/* OUT ---------------------------
Enter TestPrivateObject
 [Original] Creator 0, thread 0
 [No Name] Creator 1, thread 1
 [T]Thread 1 working
 [No Name] I am 1, thread 1
 [No Name] Creator 2, thread 0
 [T]Thread 0 working
 [No Name] I am 2, thread 0
 [T]Thread 0 finished
 [No Name] Delete 2
 [T]Thread 1 finished
 [No Name] Delete 1
 [Original] Delete 0
Quit TestPrivateObject
----------------------------------*/
// Test with private clause
void TestPrivateObject(){
 MyObject::Reset();
 Printer::Build() << "Enter TestPrivateObject" << "\n" << Printer::PRINT;
 {
 const double startTime = omp_get_wtime();
 MyObject obj("Original");

 #pragma omp parallel default(none) private(obj)
 {
 Printer::Build() << "\t[T]Thread " << omp_get_thread_num() << " working\n" << Printer::PRINT;
 obj.printid();
 while( (omp_get_wtime() - startTime) < double(omp_get_thread_num()*1.0));
 Printer::Build() << "\t[T]Thread " << omp_get_thread_num() << " finished\n" << Printer::PRINT;
 }
 }
 Printer::Build() << "Quit TestPrivateObject" << "\n" << Printer::PRINT;
 Printer::Build() << "----------------------" << "\n" << Printer::PRINT;
}

/* OUT ---------------------------
Enter TestNormal
 [Original] Creator 0, thread 0
 [T]Thread 1 working
 [Original] I am 0, thread 1
 [T]Thread 0 working
 [Original] I am 0, thread 0
 [T]Thread 0 finished
 [T]Thread 1 finished
 [Original] Delete 0
Quit TestNormal
----------------------------------*/
// Test with share default (default is usualy = share)
void TestNormal(){
 MyObject::Reset();
 Printer::Build() << "Enter TestNormal" << "\n" << Printer::PRINT;
 {
 const double startTime = omp_get_wtime();
 MyObject obj("Original");

 #pragma omp parallel //default(none)
 {
 Printer::Build() << "\t[T]Thread " << omp_get_thread_num() << " working\n" << Printer::PRINT;
 obj.printid();
 while( (omp_get_wtime() - startTime) < double(omp_get_thread_num()*1.0));
 Printer::Build() << "\t[T]Thread " << omp_get_thread_num() << " finished\n" << Printer::PRINT;
 }
 }
 Printer::Build() << "Quit TestNormal" << "\n" << Printer::PRINT;
 Printer::Build() << "---------------" << "\n" << Printer::PRINT;
}

/* OUT ---------------------------
Enter TestThreadPrivate
 [T]Thread 1 working with 0
 [T]Thread 0 working with 0
 [T]Thread 0 finished
 [T]Thread 1 finished
Quit TestThreadPrivate
----------------------------------*/
// Test with int to show that there is not any copy
void TestNumberPrivate(){
 MyObject::Reset();
 Printer::Build() << "Enter TestThreadPrivate" << "\n" << Printer::PRINT;
 {
 const double startTime = omp_get_wtime();
 int obj = 99;

 #pragma omp parallel default(none) private(obj)
 {
 Printer::Build() << "\t[T]Thread " << omp_get_thread_num() << " working with " << obj << "\n" << Printer::PRINT;
 while( (omp_get_wtime() - startTime) < double(omp_get_thread_num()*1.0));
 Printer::Build() << "\t[T]Thread " << omp_get_thread_num() << " finished\n" << Printer::PRINT;
 }
 }
 Printer::Build() << "Quit TestThreadPrivate" << "\n" << Printer::PRINT;
 Printer::Build() << "----------------------" << "\n" << Printer::PRINT;
}

/* OUT ---------------------------
Enter TestPrivateObject
 [Original] Creator 0, thread 0
 [T]Thread 0 working
 [Original] I am 0, thread 0
 [T]Thread 1 working
 [T]Thread 0 finished
 [Original] I am 0, thread 1
 [T]Thread 1 finished
 [Original] Delete 0
Quit TestPrivateObject
----------------------------------*/
// Test with private clause for pointer
void TestPrivatePointerObject(){
 MyObject::Reset();
 Printer::Build() << "Enter TestPrivateObject" << "\n" << Printer::PRINT;
 {
 const double startTime = omp_get_wtime();
 MyObject* const obj = new MyObject("Original");
 MyObject& refobj = (*obj);

 // You cannot specified ref or pointer type => this is shared
 #pragma omp parallel default(none) //private(obj) private(refobj)
 {
 Printer::Build() << "\t[T]Thread " << omp_get_thread_num() << " working\n" << Printer::PRINT;
 obj->printid();
 while( (omp_get_wtime() - startTime) < double(omp_get_thread_num()*1.0));
 Printer::Build() << "\t[T]Thread " << omp_get_thread_num() << " finished\n" << Printer::PRINT;
 }

 delete obj;
 }
 Printer::Build() << "Quit TestPrivateObject" << "\n" << Printer::PRINT;
 Printer::Build() << "----------------------" << "\n" << Printer::PRINT;
}

////////////////////////////////////////
// Class Attribute
////////////////////////////////////////

class TestAttr {
private:
 MyObject obj;
 MyObject* pobj;

public:
 /* OUT ---------------------------
 [Original] Creator 1, thread 0
 [Pointer Original] Creator 2, thread 0
 ----------------------------------*/
 TestAttr() : obj("Original"), pobj(new MyObject("Pointer Original")){
 }

 /* OUT ---------------------------
 [Pointer Original] Delete 2
 [Original] Delete 1
 ----------------------------------*/
 ~TestAttr(){
 delete pobj;
 }

 /* OUT ---------------------------
 Enter TestAttr::testShareObject
 [T]Thread 1 working
 [Original] I am 1, thread 1
 [T]Thread 0 working
 [Original] I am 1, thread 0
 [T]Thread 0 finished
 [T]Thread 1 finished
 Quit TestAttr::TestShareObject
 ----------------------------------*/
 // Test with share clause (share is usualy = default)
 void testShareObject(){
 Printer::Build() << "Enter TestAttr::testShareObject" << "\n" << Printer::PRINT;
 {
 const double startTime = omp_get_wtime();
 //erreur: ‘TestAttr::obj’ is not a variable in clause ‘shared’
 #pragma omp parallel default(none) //shared(obj)
 {
 Printer::Build() << "\t[T]Thread " << omp_get_thread_num() << " working\n" << Printer::PRINT;
 obj.printid();
 while( (omp_get_wtime() - startTime) < double(omp_get_thread_num()*1.0));
 Printer::Build() << "\t[T]Thread " << omp_get_thread_num() << " finished\n" << Printer::PRINT;
 }
 }
 Printer::Build() << "Quit TestAttr::TestShareObject" << "\n" << Printer::PRINT;
 Printer::Build() << "--------------------" << "\n" << Printer::PRINT;
 }

 /* OUT ---------------------------
 Enter TestAttr::testPrivateObject
 [T]Thread 1 working
 [Original] I am 1, thread 1
 [T]Thread 0 working
 [Original] I am 1, thread 0
 [T]Thread 0 finished
 [T]Thread 1 finished
 Quit TestAttr::TestPrivateObject
 ----------------------------------*/
 // Test with private clause
 void testPrivateObject(){
 Printer::Build() << "Enter TestAttr::testPrivateObject" << "\n" << Printer::PRINT;
 {
 const double startTime = omp_get_wtime();
 //erreur: ‘TestAttr::obj’ is not a variable in clause ‘private’
 #pragma omp parallel default(none) //private(obj)
 {
 Printer::Build() << "\t[T]Thread " << omp_get_thread_num() << " working\n" << Printer::PRINT;
 obj.printid();
 while( (omp_get_wtime() - startTime) < double(omp_get_thread_num()*1.0));
 Printer::Build() << "\t[T]Thread " << omp_get_thread_num() << " finished\n" << Printer::PRINT;
 }
 }
 Printer::Build() << "Quit TestAttr::TestPrivateObject" << "\n" << Printer::PRINT;
 Printer::Build() << "----------------------" << "\n" << Printer::PRINT;
 }

 /* OUT ---------------------------
 Enter TestAttr::testSharePointer
 [T]Thread 0 working
 [Pointer Original] I am 2, thread 0
 [T]Thread 1 working
 [T]Thread 0 finished
 [Pointer Original] I am 2, thread 1
 [T]Thread 1 finished
 Quit TestAttr::TestShareObject
 ----------------------------------*/
 // Test with share clause (share is usualy = default)
 void testSharePointer(){
 Printer::Build() << "Enter TestAttr::testSharePointer" << "\n" << Printer::PRINT;
 {
 const double startTime = omp_get_wtime();
 //erreur: ‘TestAttr::pobj’ is not a variable in clause ‘shared’
 #pragma omp parallel default(none) //shared(pobj)
 {
 Printer::Build() << "\t[T]Thread " << omp_get_thread_num() << " working\n" << Printer::PRINT;
 pobj->printid();
 while( (omp_get_wtime() - startTime) < double(omp_get_thread_num()*1.0));
 Printer::Build() << "\t[T]Thread " << omp_get_thread_num() << " finished\n" << Printer::PRINT;
 }
 }
 Printer::Build() << "Quit TestAttr::TestShareObject" << "\n" << Printer::PRINT;
 Printer::Build() << "--------------------" << "\n" << Printer::PRINT;
 }

 /* OUT ---------------------------
 Enter TestAttr::testPrivatePointer
 [T]Thread 0 working
 [Pointer Original] I am 2, thread 0
 [T]Thread 1 working
 [T]Thread 0 finished
 [Pointer Original] I am 2, thread 1
 [T]Thread 1 finished
 Quit TestAttr::TestPrivateObject
 ----------------------------------*/
 // Test with private clause
 void testPrivatePointer(){
 Printer::Build() << "Enter TestAttr::testPrivatePointer" << "\n" << Printer::PRINT;
 {
 const double startTime = omp_get_wtime();
 //erreur: ‘TestAttr::pobj’ is not a variable in clause ‘private’
 #pragma omp parallel default(none) //private(pobj)
 {
 Printer::Build() << "\t[T]Thread " << omp_get_thread_num() << " working\n" << Printer::PRINT;
 pobj->printid();
 while( (omp_get_wtime() - startTime) < double(omp_get_thread_num()*1.0));
 Printer::Build() << "\t[T]Thread " << omp_get_thread_num() << " finished\n" << Printer::PRINT;
 }
 }
 Printer::Build() << "Quit TestAttr::TestPrivateObject" << "\n" << Printer::PRINT;
 Printer::Build() << "----------------------" << "\n" << Printer::PRINT;
 }
};

////////////////////////////////////////
// Main
////////////////////////////////////////

int main(int argc, char* argv[]){

 TestShareObject();
 TestPrivateObject();
 TestNormal();
 TestNumberPrivate();

 TestPrivatePointerObject();

 // Attribute are always share!
 TestAttr test;
 test.testShareObject();
 test.testPrivateObject();
 test.testSharePointer();
 test.testPrivatePointer();

 return 0;
}
Enjoyed reading this post?
Subscribe to the RSS feed and have all new posts delivered straight to you.

Comments are closed.

Celadon theme by the Themes Boutique