Community
cancel
Showing results for 
Search instead for 
Did you mean: 
worc1154
Beginner
50 Views

Problem with parallel_reduce

Hi,
I'm tring to use parallel reduce in a numerical algorithm, so, I have constructed a class with two constructors, one to make the original object, and one to act as a copy function. It also has the methods operator(), join and a destructor. The difficultt that I am having is that it appears to be calling the destructor after calling the operator method, but before it has called the join method. This means that when the join method is called and it trys to change the arrangement of some of the allocated memory errors occure.

I'm using tbb21_20080605oss_win, on a Windows XP machine, and MS Visual Studio 2005. If anyone could tell me why this is occuring and if there is a way round it I would be most greatful. Incidentally it appears to be calling this destructor on the original object that is passed into parallel_reduce, but surly should not be disposed of until the rest of the program has finished with it?

Daniel
0 Kudos
5 Replies
AJ13
New Contributor I
50 Views

Please supply some sample source code that illustrates your problem. Is it possible that you are copying objects yourself, and they are properly being destructed before join() is called?

I lurk on #tbb on irc.freenode.net if you want some live help I can go through the code.

AJ
worc1154
Beginner
50 Views

Hi AJ,
Thanks for the response, it is quite likely that I am making a school boy error, but I cannot see it myself, so a gentle push in the right direction would be appreciated. I have attached an example program and its output demonstrating the problem that I am having.

All the best

Daniel

Constructor of object 1
calling the operator of object 1
calling the operator of object 1
calling the operator of object 1
Constructor of object 2
calling the destructor of object 1
calling the operator of object 2
calling the join of object 1 and 2
calling the destructor of object 2

#include "stdafx.h"
#include
#include
#include
#include "tbb/task_scheduler_init.h"
#include "tbb/parallel_reduce.h"
#include "tbb/blocked_range.h"


using namespace tbb;
using namespace std;

class ExampleClass {
public:
int node, iterations;

ExampleClass(int iterations) : node(1), iterations(iterations)
{printf("Constructor of object %i ", node);}

ExampleClass(ExampleClass x, split) : node(x.node+1)
{printf("Constructor of object %i ", node);}

~ExampleClass()
{
printf("calling the destructor of object %i ", node);
}

//base case output from this is T1 holding A*Q, S holding
//the singular values and Q holding the singular vectors
void operator()( const blocked_range& r )
{
printf("calling the operator of object %i ", node);
}

void join(const ExampleClass& y)
{
printf("calling the join of object %i and %i ", node, y.node);
}
};

int main()
{
task_scheduler_init init;

ExampleClass s(1000);
parallel_reduce(blocked_range(0, 30, 10), s);
scanf("%i");
}

AJ13
New Contributor I
50 Views

You forgot to check how the copy constructor is called. It appears from looking at the source for parallel_reduce that the copy constructor is called on one child of the split, and the split copy constructor is called for the other child. So this means that the official TBB documentation should be updated to include the fact that the Body template must have the copy constructor defined as well.

AJ
worc1154
Beginner
50 Views

Hi,
Thanks for the help, the use of the compiler shallow copy explains the problem.

I still don't understand though why the copy is used at all, because it would appear that the copied object is only used in the call to the split constructor before it is destroyed? I now get the output below from my updated code. Under what other conditions would the copied object actually be called? I ask because I don't want to have to copy some relatively large array's just to delete them again.

Many thanks again

Daniel

Constructor of object 1.0
Starting parallel reduce
calling the operator of object 1.0
calling the operator of object 1.0
Copy of object 1.0, making object 1.1
Constructor of object 2.0 from object 1.1
calling the destructor of object 1.1

calling the operator of object 2.0
Copy of object 2.0, making object 2.1
Constructor of object 3.0 from object 2.1
calling the destructor of object 2.1

calling the operator of object 3.0
calling the join of object 2.0 and 3.0
calling the destructor of object 3.0
calling the join of object 1.0 and 2.0
calling the destructor of object 2.0
Ending parallel reduce


#include "stdafx.h"
#include
#include
#include
#include "tbb/task_scheduler_init.h"
#include "tbb/parallel_reduce.h"
#include "tbb/blocked_range.h"


using namespace tbb;
using namespace std;

class ExampleClass {
public:
int node, copy, iterations;

ExampleClass(int iterations) : node(1), copy(0), iterations(iterations)
{printf("Constructor of object %i.%i ", node, copy);}

ExampleClass(ExampleClass x, split) : node(x.node+1)
{printf("Constructor of object %i.%i from object %i.%i ", node, copy, x.node, x.copy);}

ExampleClass(ExampleClass &x) : node(x.node), copy(x.copy +1)
{printf("Copy of object %i.%i, making object %i.%i ", node, copy-1, node, copy);}

~ExampleClass()
{
printf("calling the destructor of object %i.%i ", node, copy);
}

//base case output from this is T1 holding A*Q, S holding
//the singular values and Q holding the singular vectors
void operator()( const blocked_range& r )
{
printf("calling the operator of object %i.%i ", node, copy);
}

void join(const ExampleClass& y)
{
printf("calling the join of object %i.%i and %i.%i ", node, copy, y.node, y.copy);
}
};

int main()
{
task_scheduler_init init;

ExampleClass s(1000);
printf("Starting parallel reduce ");
parallel_reduce(blocked_range(0, 30, 10), s);
printf("Ending parallel reduce ");
scanf("%i");
}
worc1154
Beginner
50 Views

Hi,
Forget my last question, the actual problem was just that I had failed to derefference the class passed into the split constructor. As I suspected a school boy error.

Many thanks for all your help

Daniel
Reply