concurrent_vector是一個動態可增長的數字,當其他線程對其中的元素操作時,可安全push元素到concurrent_vector,對於安全並行增加元素,concurrent_vector有3個方法支持動態數組的使用:push_back, grow_by以及grow_to_at_least。
方法push_back(x)安全把x賦給array,方法grow_by(n)安全賦值n個連續的元素,利用T()來初始化,這2個方法返回一個迭代器,指向第一個元素,每個元素使用T()來初始化,例如,下面程序安全的把C風格的字符串賦給一個共享的vector中:
void Append( concurrent_vector<char>& vector, const char* string ) {
size_t n = strlen(string)+1;
std::copy( string, string+n, vector.grow_by(n) );
}
方法grow_to_at_least(n)增加vector到n,當它較短時。
方法size()返回vector的元素數量,它可能包括仍然同步構建的元素,通過方法push_back, grow_by或者grow_to_at_least。這個例子使用std::copy和iterators,而不是strcpy和pointers,因爲concurrent_vector裏的元素不可能是連續尋址,當concurrent_vector正在增加時,使用iterators是安全的,只要iterators沒有遭遇end()。然而,iterator可能引用一個遭受並行建設的元素,你一定要同步建設和訪問。
concurrent_vector從來沒有移除元素直到array被clear掉。
Clearing is Not Concurrency Safe
注意:當concurrent_vector增加時,對concurrent_vector操作是安全的,clear或者摧毀一個vector不是安全的,如果有其他對concurrent_vector的操作不要調用方法clear()。
Advanced Idiom: Waiting on an Element
有時一個線程一定等待一個元素v[i],這個元素由其他線程同步添加:
- 等到
i<v.size() ,在這之後,v[i]被分配,但是也許沒有被構建。 - 等到v[i]被構建。
一個好的方法實現步驟2是等待這個元素的atomic flag變成non-zero,爲了確保flag是zero,需要做:
- 使用分配zeroed內存的分配器來實例化concurrent_vector,例如tbb::zero_allocator。
- 讓元素的構造函數設置這個flag成non-zero,作爲最後的行爲。
下面是一個例子,vector元素是一個atomic指針,假設添加到vector的指針是non-NULL:
#include tbb/compat/thread
#include tbb/tbb_allocator.h // zero_allocator defined here
#include tbb/atomic.h
#include tbb/concurrent_vector.h
using namespace tbb;
typedef concurrent_vector<atomic<Foo*>, zero_allocator<atomic<Foo*> > >
FooVector;
Foo* FetchElement( const FooVector& v, size_t i ) {
// Wait for ith element to be allocated
while( i>=v.size() )
std::this_thread::yield();
// Wait for ith element to be constructed
while( v[i]==NULL )
std::this_thread::yield();
return v[i];
}
通常,這個flag一定是atomic類型,目的確保適當的內容一致性。