- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I have one example: in my caller code, I would like to run a section of code in parallel, so I created a two task which then call a one task twice. Code looks like this:
class TwoTask: public tbb::task {
class TOneTask: public tbb::task {
public:
tbb::task* execute() {
// my implementation
}
OneTask( ...)
};
public:
tbb::task* execute() {
OneTask& a = *new( tbb::task::allocate_child() ) OneTask();
OneTask& b = *new( tbb::task::allocate_child() ) OneTask();
set_ref_count(2);
spawn(a);
return &b;
}
TwoTask () {}
};
// in my caller code
TwoTask &cefft = *new( tbb::task::allocate_root() )TwoTask (,,,);
tbb::task::spawn_root_and_wait(cefft);
cefft.destroy(cefft);
The problem is I always get segment violation when I run with 2 threads. But if I remove the spawn code, replace just the execute() function, so the code run in serial mode, everything is fine. There is no overlap memory write between two onetasks.
What is wrong with this code? Please help.
Thanks.
class TwoTask: public tbb::task {
class TOneTask: public tbb::task {
public:
tbb::task* execute() {
// my implementation
}
OneTask( ...)
};
public:
tbb::task* execute() {
OneTask& a = *new( tbb::task::allocate_child() ) OneTask();
OneTask& b = *new( tbb::task::allocate_child() ) OneTask();
set_ref_count(2);
spawn(a);
return &b;
}
TwoTask () {}
};
// in my caller code
TwoTask &cefft = *new( tbb::task::allocate_root() )TwoTask (,,,);
tbb::task::spawn_root_and_wait(cefft);
cefft.destroy(cefft);
The problem is I always get segment violation when I run with 2 threads. But if I remove the spawn code, replace just the execute() function, so the code run in serial mode, everything is fine. There is no overlap memory write between two onetasks.
What is wrong with this code? Please help.
Thanks.
Link Copied
4 Replies
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
How about:
[cpp]tbb::task* execute() {I don't see how destroy() would not cause a problem in the caller code, though, because spawn_root_and_wait() should have destroyed its argument.
set_ref_count(2/*spawn*/+1/*wait_for_all*/);
OneTask& a = *new( tbb::task::allocate_child() ) OneTask();
OneTask& b = *new( tbb::task::allocate_child() ) OneTask();
spawn(a);
spawn_and_wait_for_all(b);
return NULL;
}
[/cpp]
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Quoting - Raf Schietekat
How about:
[cpp]tbb::task* execute() {I don't see how destroy() would not cause a problem in the caller code, though, because spawn_root_and_wait() should have destroyed its argument.
set_ref_count(2/*spawn*/+1/*wait_for_all*/);
OneTask& a = *new( tbb::task::allocate_child() ) OneTask();
OneTask& b = *new( tbb::task::allocate_child() ) OneTask();
spawn(a);
spawn_and_wait_for_all(b);
return NULL;
}
[/cpp]
Sorry, I am not sure I get it. Do you mean this is the execute for TwoTask? How about caller code? I should not spawn in the caller code?
Are you saying the "destroy" is not necessary?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Yes, this should be TwoTask::execute(), and in the caller code I would not call destroy() (does it really cause no problems?), but the rest remains the same.
(Added) Have a look at "Simple Example: Fibonacci Numbers" in the Tutorial.
(Added) Have a look at "Simple Example: Fibonacci Numbers" in the Tutorial.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Raf is right. A TBB task is by default destroyed after execution, unless the programmer explicitly recycled it. So the original code has two problems: 1) child tasks decrement reference count of a destroyed parent, and 2) explicit call to destroy() at the end is foralready destroyed task. The second one is obvious to fix. The first one should be fixed either with explicit wait for children (i.e. spawn_and_wait_for_all as Raf suggested; note that the reference counter should be 3 in this case) or with recycling the TwoTask as continuation (note that then it will run for a second time after children completion, and take care that this second invocation is a no-op).
In just-released TBB 2.2, more user-friendly ways to run code sections in parallel are available, namely tbb::parallel_invoke function and tbb::task_group class.
Reply
Topic Options
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page