Intel® oneAPI Threading Building Blocks
Ask questions and share information about adding parallelism to your applications when using this threading library.

ref_count is too small

xinyuhou
Beginner
574 Views
I encapsulate 4 functions into 4 task derivedclasses respectively and using 1 class to spawn all of them. While it is running there is an assertion said ref_count is too small. Please help me out of this problem.

Here are the 4 task derived classes, each of them call the corresponding function that is implemented in another file.

class PCalculateGA:public tbb::task{

public:

VecDoub & m_tempXValue;

MatDoub & m_ga;

double m_k;

double m_lr;

PCalculateGA(VecDoub & XValue, MatDoub & ga, double k, double lr):

m_tempXValue(XValue),m_ga(ga),m_k(k),m_lr(lr){}

task* execute(){

CalculateGA(m_tempXValue, m_ga, m_k, m_lr);

return NULL;

}

};

class PCalculateGp:public tbb::task{

public:

VecDoub & m_tempXValue;

VecDoub & m_gp;

double m_k;

double m_lr;

PCalculateGp(VecDoub & XValue, VecDoub & gp, double k, double lr):

m_tempXValue(XValue),m_gp(gp),m_k(k),m_lr(lr){}

task* execute(){

CalculateGp(m_tempXValue, m_gp, m_k, m_lr);

return NULL;

}

};

class PCalculateEp:public tbb::task{

public:

VecDoub & m_tempXValue;

VecDoub & m_ep;

double m_k;

double m_lr;

double* m_externalFore;

PCalculateEp(VecDoub & XValue, VecDoub & ep, double k, double lr, double* externalFore):

m_tempXValue(XValue),m_ep(ep),m_k(k),m_lr(lr),m_externalFore(externalFore){}

task* execute(){

CalculateEp(m_tempXValue, m_ep, m_k, m_lr, m_externalFore);

return NULL;

}

};

class PCalculateEA:public tbb::task{

public:

VecDoub & m_tempXValue;

MatDoub & m_ea;

double m_k;

double m_lr;

double* m_externalFore;

PCalculateEA(VecDoub & XValue, MatDoub & ea, double k, double lr, double* externalFore):

m_tempXValue(XValue),m_ea(ea),m_k(k),m_lr(lr),m_externalFore(externalFore){}

task* execute(){

CalculateEA(m_tempXValue, m_ea, m_k, m_lr, m_externalFore);

return NULL;

}

};

The final class that spawn above tasks is

class ParallelCalculation:public tbb::task{

public:

VecDoub & m_tempXValue;

MatDoub & m_ga;

VecDoub & m_gp;

VecDoub & m_ep;

MatDoub & m_ea;

double m_k;

double m_lr;

double* m_externalFore;

ParallelCalculation(VecDoub & XValue,MatDoub & ga, VecDoub & gp, VecDoub & ep, MatDoub & ea, double k,double lrt,double* externalFore):

m_tempXValue(XValue),m_ga(ga),m_gp(gp),m_ep(ep),m_ea(ea),m_k(k),m_lr(lrt),m_externalFore(externalFore){}

task* execute(){

set_ref_count(5);

PCalculateGA& t4 = *new(allocate_child())PCalculateGA(m_tempXValue,m_ga,m_k,m_lr);

PCalculateGp& t3 = *new(allocate_child())PCalculateGp(m_tempXValue,m_gp,m_k,m_lr);

PCalculateEp& t2 = *new(allocate_child())PCalculateEp(m_tempXValue,m_ep,m_k,m_lr,m_externalFore);

PCalculateEA& t1 = *new(allocate_child())PCalculateEA(m_tempXValue,m_ea,m_k,m_lr,m_externalFore);

spawn(t4);

spawn(t3);

spawn(t2);

spawn_and_wait_for_all(t1);

return NULL;

}

};

In the reference, it said the reference count should be set k+1, k is the number of the task. In my case, there are 4 tasks and due to spawn_and_wait_for_all, the ref_count should be set to 5. Am I right?

0 Kudos
13 Replies
RafSchietekat
Valued Contributor III
574 Views
Strange... consider parallel_invoke() instead.
0 Kudos
xinyuhou
Beginner
574 Views
I will type the assertion first here

Debug Assertion Failed!

Program:
...Jerry\Desktop\Project\TenSegrityDemo\Debug\TenSegrityDemo.exe
Module: tbb_debug.dll
File: ../../src/tbb/custom_scheduler.h
Line:329

Expression: parent.ref_count() >= (child && child ->parent() == &parent ? 2 :1)
ref_count is too small

And in my program, it used to be

CalculateGA(xValue, ga, kcable, lr);

CalculateGp(xValue, gp, kcable ,lr);

CalculateEp(xValue, ep, kcable, lr,externalFore);

CalculateEA(xValue, ea, kcable, lr,externalFore);

And the tbb version is like

ParallelCalculation& a = *new(task::allocate_root())ParallelCalculation(xValue,ga,gp,ep,ea,kcable,lr,externalFore);

a.spawn_and_wait_for_all(a);/* is this place right? in the example it should be task::spawn_and_wait_for_all
(a), but compiler will not get through and say task::spawn_and_wait_for_all' : illegal call of non-static member function*/

I have not write anything about scheduler initiation and commented out any other tbb program so I am sure there is no side effect from outside of this function.

0 Kudos
RafSchietekat
Valued Contributor III
574 Views
Have you tried to run the same program with the bodies emptied out? Maybe something is writing where it shouldn't (just a wild guess)...
0 Kudos
SergeyKostrov
Valued Contributor II
574 Views
Quoting xinyuhou
...
Module: tbb_debug.dll
File: ../../src/tbb/custom_scheduler.h
Line:329

Expression: parent.ref_count() >= (child && child ->parent() == &parent ? 2 : 1) ref_count is too small

[SergeyK] I saw that piece of code. Please see my comments below.

And in my program, it used to be

CalculateGA(xValue, ga, kcable, lr);
CalculateGp(xValue, gp, kcable ,lr);
CalculateEp(xValue, ep, kcable, lr,externalFore);
CalculateEA(xValue, ea, kcable, lr,externalFore);
...

[SergeyK]Unfortunately, it doesn't helpsince it is hard to reproduce your problem without a simple test-case.


Here are a couple of comments:

1. Try to debug and step into the 'parent.ref_count()' method in order to see what exactly happens there at run-time (!)

2. If you decide to debug you need to do the following:

- open 'tbb.vcproj'
- change aconfiguration to Debug ( I assume that you useWin32 Platform )
- set a host application in: 'Configuration Properties' -> 'Debugging' -> 'Command' ->a path to your test application
compiled in Debug configuration
- set a breakpointon the line 329 ( or 328 ) in 'custom_scheduler.h'
- press F10 to start debugging

3. Ialsorecommend to step into the'child->parent()' method

4. Take into account thatthe assert is only displayed in Debug configuration but its is not clear for me if this is a warning or indication of some
problem with implementation of your codes

5. What is your TBB version?

Best regards,
Sergey

0 Kudos
xinyuhou
Beginner
574 Views
em sounds really complicated. But still I will try to follow it. Many thanks!

Jerry
0 Kudos
xinyuhou
Beginner
574 Views

Guess I know where is wrong. I set a breakpoint at a.spawn_and_wait_for_all(a); and stepped into it. Found void spawn_and_wait_for_all( task& child ) was called instead of static void spawn_root_and_wait( task& root ). Like I said in the example it was task::spawn_and_wait_for_all which I guess it would call the later one since task:: indicates this is a static function. But when I use task::spawn_and_wait_for_all(a) compiler give me an error saying task::spawn_and_wait_for_all' : illegal call of non-static member function. Apparently there is a static function corresponding to the that call but the compiler just stupidly can not match it -_-||

Regards

Jerry

0 Kudos
xinyuhou
Beginner
574 Views
OMG How careless I am! It should be task::spawn_root_and_wait(a); I was typing to task::spawn_and_wait_for_all(a); No doubt it always calls void spawn_and_wait_for_all( task& child )

Best Regards

Jerry
0 Kudos
SergeyKostrov
Valued Contributor II
574 Views
Quoting xinyuhou
em sounds really complicated. But still I will try to follow it. Many thanks!

Jerry


Did you follow my instructions for debugging of 'tbb_debug.dll'? Did you have any issues or problems?

I need your feedback because I plan to make apost called "Tips for debugging IntelTBB library". Thanks in advance.

Best regards,
Sergey

0 Kudos
RafSchietekat
Valued Contributor III
574 Views
What is the status now? I don't quite understand #11 and #12...

If the problem is not yet solved after all, consider splitting up the spawn_and_wait_for_all() into spawn() and wait_for_all(), tracing ref_count() after each spawn() (it should have decreased by at most the number of preceding spawn() calls), and again in a loop until it reaches 1 just before wait_for_all(). If that doesn't reveal anything, merge spawn_and_wait_for_all() again and do the loop until ref_count() reaches 2. Or the other way around of course.
0 Kudos
SergeyKostrov
Valued Contributor II
574 Views
What is the status now? I don't quite understand #11 and #12...

I understood that Jerry found a typing "error"in his sources. He used a different spawn-like method...
0 Kudos
RafSchietekat
Valued Contributor III
574 Views
I don't see it. Oh well, never mind.
0 Kudos
SergeyKostrov
Valued Contributor II
574 Views
I don't see it...


Please take a look at Post #11:

...Found void spawn_and_wait_for_all( task& child ) was called instead of static void spawn_root_and_wait( task& root )...

0 Kudos
RafSchietekat
Valued Contributor III
574 Views
Ah, for spawning the ParallelCalculation instance (I now presume)... OK, got it. :-)
0 Kudos
Reply