Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix incorrect resize behavior with first_block #735

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions include/oneapi/tbb/concurrent_vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,23 @@ class concurrent_vector
}
}

segment_type nullify_segment( segment_table_type table, size_type segment_index ) {
segment_type target_segment{nullptr};
pavelkumbrasev marked this conversation as resolved.
Show resolved Hide resolved
if (segment_index >= this->my_first_block) {
target_segment = table[segment_index].load(std::memory_order_relaxed);
table[segment_index].store(nullptr, std::memory_order_relaxed);
} else {
target_segment = table[segment_index].load(std::memory_order_relaxed);
pavelkumbrasev marked this conversation as resolved.
Show resolved Hide resolved
if (segment_index == 0) {
for (size_type i = 0; i < this->my_first_block; ++i) {
table[i].store(nullptr, std::memory_order_relaxed);
}
}
}

return target_segment;
}

void deallocate_segment( segment_type address, segment_index_type seg_index ) {
segment_element_allocator_type segment_allocator(base_type::get_allocator());
size_type first_block = this->my_first_block.load(std::memory_order_relaxed);
Expand Down
6 changes: 6 additions & 0 deletions include/oneapi/tbb/detail/_concurrent_unordered_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,12 @@ class concurrent_unordered_base {
return new_segment;
}

segment_type nullify_segment( typename base_type::segment_table_type table, size_type segment_index ) {
segment_type target_segment = table[segment_index].load(std::memory_order_relaxed);
table[segment_index].store(nullptr, std::memory_order_relaxed);
return target_segment;
}

// deallocate_segment is required by the segment_table base class, but
// in unordered, it is also necessary to call the destructor during deallocation
void deallocate_segment( segment_type address, size_type index ) {
Expand Down
4 changes: 1 addition & 3 deletions include/oneapi/tbb/detail/_segment_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,7 @@ class segment_table {
}

void delete_segment( segment_index_type seg_index ) {
segment_type disabled_segment = nullptr;
// Set the pointer to the segment to NULL in the table
segment_type segment_to_delete = get_table()[seg_index].exchange(disabled_segment);
segment_type segment_to_delete = self()->nullify_segment(get_table(), seg_index);
if (segment_to_delete == segment_allocation_failure_tag) {
return;
}
Expand Down
40 changes: 40 additions & 0 deletions test/tbb/test_concurrent_vector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -710,3 +710,43 @@ TEST_CASE("container_range concept for concurrent_vector ranges") {
static_assert(test_concepts::container_range<typename tbb::concurrent_vector<int>::const_range_type>);
}
#endif // __TBB_CPP20_CONCEPTS_PRESENT

// There was a bug in concurrent_vector that was reproduced when resize marked
// segment (that owned by my_first_block) as deleted and
// on segment allocation thread is stuck waiting this segment to be published by other thread that allocated first block.
//! Testing resize behavior for case when new size lesser than old size.
//! \brief \ref regression
TEST_CASE("testing resize on sequantual mode") {
pavelkumbrasev marked this conversation as resolved.
Show resolved Hide resolved
tbb::concurrent_vector<int> v;

v.resize(382);
CHECK(v.size() == 382);
while (v.size() < 737) {
v.emplace_back();
}
CHECK(v.size() == 737);

v.resize(27);
CHECK(v.size() == 27);
while (v.size() < 737) {
v.emplace_back();
}
CHECK(v.size() == 737);

v.resize(1);
CHECK(v.size() == 1);
while (v.size() < 40) {
v.emplace_back();
}
CHECK(v.size() == 40);

v.resize(2222);
pavelkumbrasev marked this conversation as resolved.
Show resolved Hide resolved
CHECK(v.size() == 2222);
while (v.size() < 4444) {
v.emplace_back();
}
CHECK(v.size() == 4444);

v.clear();
CHECK(v.size() == 0);
}