From a66b9954f6dce4c1e8750fe41b149bcce204cffc Mon Sep 17 00:00:00 2001 From: songgaoye Date: Sun, 25 Oct 2026 12:03:41 +0800 Subject: [PATCH] fix: preserve lvalues in execution queue --- src/bthread/execution_queue_inl.h | 11 ++++-- test/bthread_execution_queue_unittest.cpp | 41 +++++++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/bthread/execution_queue_inl.h b/src/bthread/execution_queue_inl.h index 1a41f7d59a..2a85d27beb 100644 --- a/src/bthread/execution_queue_inl.h +++ b/src/bthread/execution_queue_inl.h @@ -302,7 +302,7 @@ friend class TaskIterator; int execute(typename butil::add_const_reference::type task, const TaskOptions* options, TaskHandle* handle) { - return execute(std::forward(const_cast(task)), options, handle); + return execute_impl(task, options, handle); } @@ -312,6 +312,13 @@ friend class TaskIterator; int execute(T&& task, const TaskOptions* options, TaskHandle* handle) { + return execute_impl(std::move(task), options, handle); + } + +private: + template + int execute_impl(U&& task, + const TaskOptions* options, TaskHandle* handle) { if (stopped()) { return EINVAL; } @@ -324,7 +331,7 @@ friend class TaskIterator; return_task_node(node); return ENOMEM; } - new (mem) T(std::forward(task)); + new (mem) T(std::forward(task)); node->stop_task = false; TaskOptions opt; if (options) { diff --git a/test/bthread_execution_queue_unittest.cpp b/test/bthread_execution_queue_unittest.cpp index 2e19a7b2fe..066417a5ba 100644 --- a/test/bthread_execution_queue_unittest.cpp +++ b/test/bthread_execution_queue_unittest.cpp @@ -150,6 +150,47 @@ TEST_F(ExecutionQueueTest, rvalue) { } } +class CopyMoveTask { +public: + explicit CopyMoveTask(int value) : _value(value), _moved(false) {} + + CopyMoveTask(const CopyMoveTask& rhs) + : _value(rhs._value), _moved(false) {} + + CopyMoveTask(CopyMoveTask&& rhs) noexcept + : _value(rhs._value), _moved(false) { + rhs._moved = true; + } + + int value() const { return _value; } + bool moved() const { return _moved; } + +private: + int _value; + bool _moved; +}; + +int add(void* meta, bthread::TaskIterator& iter) { + int* result = static_cast(meta); + for (; iter; ++iter) { + *result += iter->value(); + } + return 0; +} + +TEST_F(ExecutionQueueTest, lvalue_is_copied) { + bthread::ExecutionQueueId queue_id; + int result = 0; + ASSERT_EQ(0, bthread::execution_queue_start(&queue_id, nullptr, + add, &result)); + CopyMoveTask task(42); + ASSERT_EQ(0, bthread::execution_queue_execute(queue_id, task)); + EXPECT_FALSE(task.moved()); + ASSERT_EQ(0, bthread::execution_queue_stop(queue_id)); + ASSERT_EQ(0, bthread::execution_queue_join(queue_id)); + EXPECT_EQ(42, result); +} + struct PushArg { bthread::ExecutionQueueId id {0}; butil::atomic total_num {0};