tbb::concurrent_vector in TBB 2.2

Concurrent vector was also significantly reworked for TBB 2.2 in all areas: interface, documentation, and internal implementation.
Let's start from the interface. Methods push_back(), grow_by(), and grow_to_at_least() return iterator now. Returning iterator instead of index allows to avoid unnecessary address calculation for just inserted item(s) when a code needs to access it right after insertion:


// typedef tbb::concurrent_vector< std::pair<int,int> > cv_t;
cv_t::iterator it = cv.push_back( item ); // add new item
map[ item.first ] = &( *it ); // store its address in a table


For grow_to_at_least() which previously returned nothing, there is additional benefit of delimiting a range that was allocated and initialized by this particular call and thread. E.g.:


cv_t cv( 100 ); // initial 100 items
assert( &( *cv.grow_to_at_least(50) ) == &cv[50] ); // doesn't allocate items
assert( &( *cv.grow_to_at_least(250) ) == &cv[100] ); // allocates additional 150 items


The vector contains 100 items. grow_to_at_least(50) will return an iterator pointing to an item with index = 50. But sequential grow_to_at_least(250) will return iterator which points to item #100. It means that additional 150 (= 250 - 100) items were added by this call.
It makes more sense in concurrent environment, as these items were correctly initialized but not just allocated. The same guarantee is already provided for grow_by() and all its items.
If you wonder how items may be allocated but not initialized, please read my blog which clarifies semantics of size() and grow_to_at_least() which were also fixed in 2.2 to allow safe parallel inspections. BTW, tbb::zero_allocator was added to support use cases from this blog.

In order to align with std::vector from C++0x, method compact() was renamed as shrink_to_fit(). However, it doesn't suggest any change to semantics and practical means of the method. It still will defragment the first segments as described in my another blog, and it will not change capacity exactly to the value of size().

To close the topic of interface changes, I'd remind you that you might compile old programs with new TBB as is just by setting TBB_DEPRECATED=1 as described in transition blog.

Another part of the changes is hidden behind implementation and the fact that exceptions are rare for concurrent_vector. So, a few chronic critical bugs of exception safety were fixed to comply with declared guarantees. However, these fixes miss the 2.2 release and available only in consequent stable and update releases.
So, please consider upgrading to the latest TBB after the 2.2 release in order to avoid a deadlock inside concurrent_vector which may occur for e.g. "out of memory" exception in all the previous versions.

Пожалуйста, обратитесь к странице Уведомление об оптимизации для более подробной информации относительно производительности и оптимизации в программных продуктах компании Intel.