Skip to content

Commit 0d73df4

Browse files
kboyarinovisaevil
andauthored
Fix concurrent_bounding_queue capacity on copy, move and swap operations (#1609)
Co-authored-by: Ilya Isaev <[email protected]>
1 parent 8dea30c commit 0d73df4

File tree

2 files changed

+52
-6
lines changed

2 files changed

+52
-6
lines changed

include/oneapi/tbb/concurrent_queue.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2005-2023 Intel Corporation
2+
Copyright (c) 2005-2025 Intel Corporation
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -48,7 +48,6 @@ std::pair<bool, ticket_type> internal_try_pop_impl(void* dst, QueueRep& queue, A
4848

4949
// A high-performance thread-safe non-blocking concurrent queue.
5050
// Multiple threads may each push and pop concurrently.
51-
// Assignment construction is not allowed.
5251
template <typename T, typename Allocator = tbb::cache_aligned_allocator<T>>
5352
class concurrent_queue {
5453
using allocator_traits_type = tbb::detail::allocator_traits<Allocator>;
@@ -317,7 +316,6 @@ namespace d2 {
317316
// A high-performance thread-safe blocking concurrent bounded queue.
318317
// Supports boundedness and blocking semantics.
319318
// Multiple threads may each push and pop concurrently.
320-
// Assignment construction is not allowed.
321319
template <typename T, typename Allocator = tbb::cache_aligned_allocator<T>>
322320
class concurrent_bounded_queue {
323321
using allocator_traits_type = tbb::detail::allocator_traits<Allocator>;
@@ -376,12 +374,14 @@ class concurrent_bounded_queue {
376374
concurrent_bounded_queue( const concurrent_bounded_queue& src, const allocator_type& a ) :
377375
concurrent_bounded_queue(a)
378376
{
377+
my_capacity = src.my_capacity;
379378
my_queue_representation->assign(*src.my_queue_representation, my_allocator, copy_construct_item);
380379
}
381380

382381
concurrent_bounded_queue( const concurrent_bounded_queue& src ) :
383382
concurrent_bounded_queue(queue_allocator_traits::select_on_container_copy_construction(src.get_allocator()))
384383
{
384+
my_capacity = src.my_capacity;
385385
my_queue_representation->assign(*src.my_queue_representation, my_allocator, copy_construct_item);
386386
}
387387

@@ -420,6 +420,7 @@ class concurrent_bounded_queue {
420420
if (my_queue_representation != other.my_queue_representation) {
421421
clear();
422422
my_allocator = other.my_allocator;
423+
my_capacity = other.my_capacity;
423424
my_queue_representation->assign(*other.my_queue_representation, my_allocator, copy_construct_item);
424425
}
425426
return *this;
@@ -435,6 +436,7 @@ class concurrent_bounded_queue {
435436
my_queue_representation->assign(*other.my_queue_representation, other.my_allocator, move_construct_item);
436437
other.clear();
437438
my_allocator = std::move(other.my_allocator);
439+
my_capacity = other.my_capacity;
438440
}
439441
}
440442
return *this;
@@ -547,8 +549,10 @@ class concurrent_bounded_queue {
547549

548550
private:
549551
void internal_swap( concurrent_bounded_queue& src ) {
550-
std::swap(my_queue_representation, src.my_queue_representation);
551-
std::swap(my_monitors, src.my_monitors);
552+
using std::swap;
553+
swap(my_queue_representation, src.my_queue_representation);
554+
swap(my_capacity, src.my_capacity);
555+
swap(my_monitors, src.my_monitors);
552556
}
553557

554558
static constexpr std::ptrdiff_t infinite_capacity = std::ptrdiff_t(~size_type(0) / 2);

test/tbb/test_concurrent_queue.cpp

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (c) 2005-2023 Intel Corporation
2+
Copyright (c) 2005-2025 Intel Corporation
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -282,3 +282,45 @@ TEST_CASE("Test clear and dtor with TrackableItem") {
282282
test_tracking_dtors_on_clear<oneapi::tbb::concurrent_queue<TrackableItem>>();
283283
test_tracking_dtors_on_clear<oneapi::tbb::concurrent_bounded_queue<TrackableItem>>();
284284
}
285+
286+
//! \brief \ref regression
287+
TEST_CASE("test capacity on modifying operations") {
288+
// Test that concurrent_bounded_queue capacity is preserved on copying, moving and swapping
289+
using queue_type = oneapi::tbb::concurrent_bounded_queue<int>;
290+
using capacity_type = typename queue_type::size_type;
291+
292+
queue_type q;
293+
capacity_type desired_capacity = 64;
294+
295+
q.set_capacity(desired_capacity);
296+
REQUIRE_MESSAGE(q.capacity() == desired_capacity, "Capacity is not set correctly");
297+
298+
queue_type q_copy(q);
299+
REQUIRE_MESSAGE(q_copy.capacity() == desired_capacity, "Capacity is not preserved on copying");
300+
301+
queue_type q_move(std::move(q));
302+
REQUIRE_MESSAGE(q_move.capacity() == desired_capacity, "Capacity is not preserved on moving");
303+
304+
queue_type different_capacity_q1;
305+
different_capacity_q1.set_capacity(desired_capacity * 2);
306+
307+
different_capacity_q1 = q_move;
308+
REQUIRE_MESSAGE(different_capacity_q1.capacity() == desired_capacity,
309+
"Capacity is not preserved on copy assignment");
310+
311+
queue_type different_capacity_q2;
312+
different_capacity_q2.set_capacity(desired_capacity * 2);
313+
314+
different_capacity_q2 = std::move(q_move);
315+
REQUIRE_MESSAGE(different_capacity_q2.capacity() == desired_capacity,
316+
"Capacity is not preserved on move assignment");
317+
318+
queue_type different_capacity_q3;
319+
different_capacity_q3.set_capacity(desired_capacity * 2);
320+
321+
different_capacity_q3.swap(different_capacity_q2);
322+
REQUIRE_MESSAGE(different_capacity_q3.capacity() == desired_capacity,
323+
"Capacity is not preserved on swap");
324+
REQUIRE_MESSAGE(different_capacity_q2.capacity() == desired_capacity * 2,
325+
"Capacity is not preserved on swap");
326+
}

0 commit comments

Comments
 (0)