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.
Subscribe to the RSS feed and have all new posts delivered straight to you.
