【问题标题】: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,没有找到匹配的重载函数,我看不到这里缺少什么。

【问题讨论】:

    标签: c++ multithreading parallel-processing


    【解决方案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&amp; operator=(ThreadGuard&amp;&amp;) noexcept = default; 我觉得不对,你自己写吧。您需要检查this-&gt;t 是否可加入(并加入),然后再覆盖它。
    • @MikeVine 在这种情况下,默认行为(OP 也有)将调用std::terminate。它可能是也可能不是 OP 想要的,但我只是在答案中保持了相同的逻辑。
    • 是的 OP 也有这个错误 (?)。这将是一个 非常 奇怪的类,在这种情况下不会自行清理。它很容易修复 - 或者如果你真的想在那种情况下终止,那么明确似乎是正确的。
    • @MikeVine 我想说的是品味问题。这个瘦包装器的行为与std::thread 一样,只是它在销毁时自动加入。另一方面,std::jthread 有一个更智能的移动赋值运算符,它调用request_stop(),然后调用join()。对于类似于使用std::thread 的东西,需要添加一个需要检查的原子。只是join()ing 可能会导致各种麻烦。
    • 1+ 以获得完整答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-26
    • 1970-01-01
    • 1970-01-01
    • 2020-02-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多