C++ 尝试使用移动语义创建threadguard

C++ 尝试使用移动语义创建threadguard,c++,multithreading,parallel-processing,C++,Multithreading,Parallel Processing,这个标题不言自明。我试图获得一个线程保护的最小工作示例,它也可以支持std::threads所具有的移动语义 #include <iostream> #include <thread> #include <vector> #include <functional> class ThreadGuard { public: explicit ThreadGuard(std::thread input): t(std::move(input))

这个标题不言自明。我试图获得一个线程保护的最小工作示例,它也可以支持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;
}
#包括
#包括
#包括
#包括
等级护丝板{
公众:
显式ThreadGuard(标准::线程输入):t(标准::移动(输入))
{}
~ThreadGuard(){
if(t.joinable()){
t、 join();
}
}
ThreadGuard(ThreadGuard const&t)=删除;
ThreadGuard&运算符=(ThreadGuard const&)=删除;
ThreadGuard和operator=(ThreadGuard和out){
this->t=out.transfer();
归还*这个;
}
std::线程传输(){
返回std::move(t);
}
私人:
标准:螺纹t;
};
void doWork(标准::字符串输入){

std::cout您需要将
int
转换为
std::string

tp[i] = ThreadGuard(std::thread(doWork, std::to_string(i)));
您也不需要编写自己的移动构造函数和移动分配运算符。请使用默认值

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)...)
    {}

还值得注意的是:在C++20中添加了
join()
s,在销毁时自动执行。

您需要将
int
转换为
std::string

tp[i] = ThreadGuard(std::thread(doWork, std::to_string(i)));
您也不需要编写自己的移动构造函数和移动分配运算符。请使用默认值

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)...)
    {}

另外值得注意的是:在C++20中添加了一个
join()
s自动销毁。

ThreadGuard&operator=(ThreadGuard&&)noexcept=default;
我认为这是错误的,你应该自己写。你需要检查
this->t
是否可连接(并加入它)在你写之前。@MikeVine默认行为(OP也有)在这种情况下调用
std::terminate
。这可能是OP想要的,也可能不是OP想要的,但我只是在答案中保留了相同的逻辑。是的,OP有这个错误(?)也是。在这种情况下,它将是一个非常奇怪的类,不会自行清理。修复起来很简单——或者如果你真的想在这种情况下终止,那么显式似乎是正确的。@MikeVine我想说,这是一个品味问题。这个薄包装器的行为就像
std::thread
一样,只是在销毁时自动加入。另一方面,
std::jthread
有一个更智能的移动分配操作符,它调用
request\u stop()
,然后调用
join()
。对于类似于使用
std::thread
的操作,需要添加一个需要检查的原子。只需
join()
ing可能会导致各种各样的麻烦。1+完整的答案。
ThreadGuard&operator=(ThreadGuard&&)noexcept=default;
我认为这是错误的,你应该自己写。在写之前,你需要检查
this->t
是否可连接(并连接它)。@MikeVine默认行为(OP也有)在这种情况下会调用
std::terminate
。这可能是OP想要的,也可能不是OP想要的,但我只是在答案中保留了相同的逻辑。是的,OP有这个错误(?)也是。在这种情况下,它将是一个非常奇怪的类,不会自行清理。修复起来很简单——或者如果你真的想在这种情况下终止,那么显式似乎是正确的。@MikeVine我想说,这是一个品味问题。这个薄包装器的行为就像
std::thread
一样,只是在销毁时自动加入。另一方面,
std::jthread
有一个更智能的移动分配操作符,它调用
request\u stop()
,然后调用
join()
。对于类似于使用
std::thread
的操作,需要添加一个需要检查的原子。只需
join()
ing可能会导致各种各样的麻烦。完整答案为1+。