“const std::stop_token&”或只是“std::stop_token”作为线程函数的参数?

问题描述 投票:0回答:1

由于 clang-tidy 抱怨“每次调用都会复制参数‘stop_token’,但仅用作 const 引用;考虑将其设为 const 引用”,我在问自己这个问题,为什么我找到的每个示例都是关于 std:: jthread/stop_token 按值获取 stop_token,但我没有找到任何解释。

那么,为什么要按值获取 stop_token 呢?

1) void f(std::stop_token){};
2) void f(const std::stop_token&){};

当您可以假设 stop_token 是 std::jthread 生成的时,这真的很重要吗?

编辑:提出这个问题纯粹是出于好奇,并且不要忽视“只是因为”的铿锵有力的警告。

c++ multithreading c++20
1个回答
4
投票

根据cppref

创建新的 jthread 对象并将其与执行线程关联。新的执行线程开始执行

std::invoke(std::move(f_copy), get_stop_token(), std::move(args_copy)...)
,...

std::jthread::get_stop_token
的返回类型是
std::stop_token

因此,如果您的

f
仅用于构造
std::jthread
,我相信将 const std::stop_token& 作为其第一个参数是
完全可以
。不存在终身问题。

但是如果你想在其他地方使用你的

f
,例如
std::thread
,可能会有问题。

void f(const std::stop_token&) {}
{
    std::stop_source ssrc;
    std::stop_token stk{ssrc.get_token()};
    std::thread t{f, std::ref(stk)};
}

stk
被破坏时,引用就会悬空。


大多数情况下,您应该按值传递。

因为复制

std::stop_token
std::stop_source
相对便宜。
此外,由于
std::stop_token
通常存储在 lambda 中和/或在另一个线程中使用,因此按值传递可以避免生命周期问题。

也有一些情况你可以通过引用传递。

因为与原始指针相比,它并不便宜。如果能保证生命周期的话,通过引用传递会更高效。

比如

std::stop_callback
的构造函数,因为里面会复制
std::stop_token
,所以通过引用传递会更好。

template<class C>
explicit stop_callback( const std::stop_token& st, C&& cb ) noexcept(/*see below*/);
© www.soinside.com 2019 - 2024. All rights reserved.