尝试使用移动语义创建线程保护
Posted
技术标签:
【中文标题】尝试使用移动语义创建线程保护【英文标题】:Attempting to create a threadguard with move semantics 【发布时间】:2020-08-06 20:49:34 【问题描述】:标题很容易解释。我正在尝试获得一个线程保护的最小工作示例,它还可以支持 std::threads 具有的移动语义。
#include <iostream>
#include <thread>
#include <vector>
#include <functional>
class ThreadGuard
public:
explicit ThreadGuard(std::thread input): t(std::move(input))
~ThreadGuard()
if(t.joinable())
t.join();
ThreadGuard(ThreadGuard const& t) = delete;
ThreadGuard& operator=(ThreadGuard const&) = delete;
ThreadGuard& operator=(ThreadGuard&& out)
this->t = out.transfer();
return *this;
std::thread transfer()
return std::move(t);
private:
std::thread t;
;
void doWork(std::string input)
std::cout << input << std::endl;
static const auto numThreads = 4;
int main()
std::vector<ThreadGuard> tp;
tp.reserve(numThreads);
for(auto i = 0 ; i < numThreads; ++i)
tp[i] = ThreadGuard(std::thread(doWork, i));
return 0;
目前遇到了障碍。 std::invoke,没有找到匹配的重载函数,我看不到这里缺少什么。
【问题讨论】:
【参考方案1】:您需要将int
转换为std::string
:
tp[i] = ThreadGuard(std::thread(doWork, std::to_string(i)));
您也不需要编写自己的移动构造函数和移动赋值运算符。使用default
:
class ThreadGuard
public:
explicit ThreadGuard(std::thread&& input): t(std::move(input))
ThreadGuard(ThreadGuard const& t) = delete;
ThreadGuard(ThreadGuard&&) noexcept = default;
ThreadGuard& operator=(ThreadGuard const&) = delete;
ThreadGuard& operator=(ThreadGuard&&) noexcept = default;
~ThreadGuard()
if(t.joinable())
t.join();
private:
std::thread t;
;
您还可以让转换构造函数接受线程构造函数参数并直接转发它们:
template<typename...Args>
explicit ThreadGuard(Args&&... args): t(std::forward<Args>(args)...)
这将允许它像这样创建:
tp[i] = ThreadGuard(doWork, std::to_string(i));
另外值得注意的是:在 C++20 中添加了 std::jthread
,而 join()
s 在销毁时自动添加。
【讨论】:
ThreadGuard& operator=(ThreadGuard&&) noexcept = default;
我觉得不对,你自己写吧。您需要检查this->t
是否可加入(并加入),然后再覆盖它。
@MikeVine 在这种情况下,默认行为(OP 也有)将调用std::terminate
。它可能是也可能不是 OP 想要的,但我只是在答案中保持了相同的逻辑。
是的 OP 也有这个错误 (?)。这将是一个 非常 奇怪的类,在这种情况下不会自行清理。它很容易修复 - 或者如果你真的想在那种情况下终止,那么明确似乎是正确的。
@MikeVine 我想说的是品味问题。这个瘦包装器的行为与std::thread
一样,只是它在销毁时自动加入。另一方面,std::jthread
有一个更智能的移动赋值运算符,它调用request_stop()
,然后调用join()
。对于类似于使用std::thread
的东西,需要添加一个需要检查的原子。只是join()
ing 可能会导致各种麻烦。
1+ 以获得完整答案。以上是关于尝试使用移动语义创建线程保护的主要内容,如果未能解决你的问题,请参考以下文章