There's not supposed to be a limit. The ref_count is a full word, so the system should run out of memory long before ref_count overflows.
Can you post a self-contained example to here or post a bug report to http://www.threadingbuildingblocks.org/bugzilla_search.php?
I concur with Andrey that using algorithms is the preferred way. Still someone may need to use tasks directly. There aresome rules to follow when working with TBBtasks:
In the described case, I would use continuation-passing style and allocate_additional_child_of(continuation). Also STask seems unnecessary, unless it does something else in your real code; in the simplified code, it is more efficient to spawn the very first DCTask as the root.
Many thanks to both of you A. & A.,
I think I can now fix all of the code with only a couple of additional lines. I was not aware that the scheduler needs so much additional support from outside to correctly build task hierarcies.
And yes, of course STask does a lot more work after spawning the first child. Using a continuation here seems not to be good asthese additional calculations won't execute in parallel to the DCTasks then.But I canspawn both, STask and DCTask, as root and later wait for completion of both of them (instead of STask only), that would be an alternative.
So I will use the blocking scheme first using allocate_additional_child() for the additional tasks which might get spawned.
You might take a look at http://softwareblogs.intel.com/2008/07/02/implementing-task_group-interface-in-tbb/, which has a wrapper that provides a simpler task interface.
The general philosophy behind class task is that it is a high performance engine under the hood of the algorithm templates. As such, the algorithm templates are supposed to be the way to drive it easily, and the task interface is for those who want to take on the burden to buildcustomized high-performance vehicles,
Below are some additional notes in case you would consider continuation-passing later. We have experimentally showed this style being more efficient than the blocking style.
Landmann:And yes, of course STask does a lot more work after spawning the first child. Using a continuation here seems not to be good asthese additional calculations won't execute in parallel to the DCTasks then.
If you want to spawn some tasks and then continue doing the job of the current task, you still might use the continuation.The trick is basically the same as I described above: you set_ref_count for the continuation to be one more than the actual number of children, allocate and spawn the children, then do the rest of the job, and at the very end use allocate_child to create the last, empty_task child to compensate that initial ref_count bump. For efficiency, do not even spawn the last child but instead return the pointer to it as the result of the execute method. This way you ensure maximal parallelism is used while also avoid some additional overhead of the blocking style.
Landmann:But I canspawn both, STask and DCTask, as root and later wait for completion of both of them (instead of STask only), that would be an alternative.
Yes; for this,you need to use tbb::task_list where youput both roots to, and then call spawn_root_and_wait(the_task_list).