- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I had been using blocked_range a bit, but was getting tired of writing custom functor objects all the time, so I began trying to use boost/foreach and boost/mem_fn, but got compiler errors about lack of iterator, so looked into the header and found blocked_range doesn't have iterators. It has a const_iterator, but not an iterator. Also the const_iterator isn't actually const at all.
So I added to file:blocked_range.h around line:50
//! A range over which to iterate.
/** @ingroup algorithms */
template
class blocked_range {
public:
//! Type of a value
/** Called a const_iterator for sake of algorithms that need to treat a blocked_range
as an STL container. */
typedef Value iterator; //added this here
typedef const Value const_iterator; //fixed this here
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
There is nothing preventing you from writing something like for_each, but it will have to operate on the Range concept, not use iterators. Remember that the components from STL and Boost might not mix will with TBB when it comes to parallel code. You will have to iterate over the ranges, not the elements of the blocked_range.
I've thought myself about the relation of iterators to ranges. After some thought, I came to the conclusion that iterators are not parallel at all. So long as I have a range, I can do more parallelism. As soon as I introduce the notion of an iterator, I'm writing sequential code. That's my view, and hope this answers your question as to why iterators in a blocked_range might not be a good idea.
BTW, I assume that the idea for having iterators is that within the function body that operates on a range, you want to simplify your work on those elements. I think there could be a better approach to solving that problem, though I need to think a bit on what it might be.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Note that "typedef const Value const_iterator" puts the constat the wrong level of indirection. The const needs to be on the target of the iterator. Alas, as far as I can tell there is no automatic way to map an iterator toits correspondingconst_iterator.
I was hoping that the C++0x Range
I see two possible solutions. One is to treat a range as a pointer as far as constness:
-
Add "typedef Value iterator".
-
Keep"typedef Value const_iterator" for backwards compatibility, but deprecate it.
-
Change methods "begin() const" and "end() const" to return an iterator.
The second solution is to leave blocked_range as it is, and introduce a new template "container_range
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
BTW, I assume that the idea for having iterators is that within the function body that operates on a range, you want to simplify your work on those elements. I think there could be a better approach to solving that problem, though I need to think a bit on what it might be.
Yes your right, my goal here is to make life easier to operate on the range of a container w/iterators. Thus after the range has been split for concurrency, the serial work left to do wasbecominga drag, if nothing else.
But thinking about it now that I read the posts, range can work on a simple c-array and possibly other "containers" that aren't really std-like containers at all. So its not really practical to change range for everyone.
However as an idea, with the introduction of "Concepts" for templates in C++0x, TBB could provide iterators into the range if the underlying class provides iterators. That way it could specialize as needed and make things easier when meshing with std/boost like concepts. I'm sure this could also be done now without "Concepts", but the code might become quite byzantine.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Thanks for reminding me of that (range's requirements), in my case all ranges happened to be built on std/boost-like containers so it wasn't a problem. But yes it make no sense on a int[].
Here is a simplified example:
void update()
{ //Visit all actors (Order is not critical)
tbb::parallel_for(
tbb::blocked_range
ApplyUpdate(),
tbb::auto_partitioner()
);
}
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Now I see; actor (which is the value obtained from an iterator) is updated inside so const_iterator cannot be used.
I think the best thing for the moment would beto define iterator for blocked_range, possibly deprecate const_iterator (if one needs constness, blocked_range<:CONST_ITERATOR> could be used I think); and when C++0x is supported enough, we might use concepts to implement two different kinds of blocked ranges.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
No it seems it should not be deprecated. What if in the example above is rewritten as following?
In this case, boost::for_each would probably require const_iterator over the range, wouldn't it?
Or will this code be rejected by compilers anyway, because even though the range has const_iteratore defined, it would then be recognized as a non-const iterator over actor_list_t and not allowed to use?
As my last guess seems very plausible, it seems then that ideallythe blocked_range<:ITERATOR> should only define iterator but not const_iterator, and vice versa the blocked_range<:CONST_ITERATOR> should only define the const form. I am not sure whether this can be done even with concepts, provided that "there is no automatic way to map an iterator toits correspondingconst_iterator" (and vice versa, I assume).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Now I see; actor (which is the value obtained from an iterator) is updated inside so const_iterator cannot be used.
I think the best thing for the moment would beto define iterator for blocked_range, possibly deprecate const_iterator (if one needs constness, blocked_range<:CONST_ITERATOR> could be used I think); and when C++0x is supported enough, we might use concepts to implement two different kinds of blocked ranges.
What about providing:
[cpp]TBB_PARALLEL_FOR(actor_t& a, actors_, tbb::auto_partitioner()) { a.Update(); }};[/cpp]
?
Underlying tasks will work with ranges of source container, but user functor is called for every single element in the range, so user doesn't see ranges, he works only with single elements.
Looks nice!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
TBB_PARALLEL_FOR(actor_t& a, actors_, tbb::auto_partitioner()) { a.Update(); }};
?
Isn't the following even better (with auto_partitioner by default, and other partitionerspossible)?
[cpp]tbb::parallel_for(actors.begin(),actors.end(), [](actor_t& a) { a.Update(); }); [/cpp]
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Isn't the following even better (with auto_partitioner by default, and other partitionerspossible)?
[cpp]tbb::parallel_for(actors.begin(),actors.end(), [](actor_t& a) { a.Update(); }); [/cpp]
Agreed, this is THE best solution. Now if Lambda was widespread enough...
Also Alexey's BOOST_FOREACH(const arctor_t& a, r){//non modifying work} does work as expected, I actually use that construct too, since I had already added typedef iterator to my blocked_range headers.
As for the TBB_FOR_EACH macro solution proposed, I think I could get that working, but with the weekend here, I don't have the code infront of me, but will try it next week. The main advantage being I could avoid the range operators all together, kindof a poor-mans lambda.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Isn't the following even better (with auto_partitioner by default, and other partitionerspossible)?
[cpp]tbb::parallel_for(actors.begin(),actors.end(), [](actor_t& a) {
a.Update();
});
[/cpp]
Definitely it's better... not counting that lambda support in all production compilers will be in 2010, stable implementations will be in 2012, and one can rely on them in library for the general public in 2015 when late adopters will finally upgrade their compilers :)

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page