移动具有线程作为成员变量的类的操作 [英] Move operations for a class with a thread as member variable

查看:127
本文介绍了移动具有线程作为成员变量的类的操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想扩展一些人帮助我的地方调用函数里面的lambda传递给线程所以我的工人类可以支持移动构造函数和移动 operator = ,但我有问题,我的类通过复制(或引用)绑定到线程,因此它可以访问类值 this 。其中有几个 atomic condition_variable mutex

I'm trying to expand with what some people helped me here Call function inside a lambda passed to a thread so my worker class can support a move constructor and a move operator=, but I have the problem that my class is binding this by copy (or reference) to the thread so it can access the class values. Which are several atomic<bool>, a condition_variable and a mutex.

但是当我尝试移动它,因为线程绑定到其他条件变量, mutex atomic s,我做的任何东西都不工作。如何解决这个问题?
我需要使用一个更复杂的对象,并移动它而不是lambda,所以线程可以有一个referenece吗?或有另一种选择。

But when I try to move it since the thread is bound to the other condition variable, mutex and atomics, anything I do on it is not working. How can I fix this? Do I need to use a more complex object and move it around instead of a lambda so the thread can have a referenece to it? or is there another alternative. As always help will be really appreciated :).

这是一个实现的代码片段(MWE)。

Here is a snippet (MWE) of the implementation.

class worker {
public:
    template <class Fn, class... Args>
    explicit worker(Fn func, Args... args) {
        t = std::thread(
            [&func, this](Args... cargs) -> void {
                std::unique_lock<std::mutex> lock(mtx);
                while (true) {
                    cond.wait(lock, [&]() -> bool { return ready; });

                    if (terminate)
                        break;

                    func(cargs...);

                    ready = false;
                }
            },
            std::move(args)...);
    }

    worker(worker &&w) : t(std::move(w.t)) { /* here there is trouble  */ }

    worker &operator=(worker &&w) {
        t = std::move(w.t);
        terminate.store(wt.terminate);
        ready.store(wt.ready);
        return *this; 
        /* here too */
    }

    ~worker() {
        terminate = true;
        if (t.joinable()) {
            run_once();
            t.join();
        }
    }

    worker() {}

    void run_once() {
        std::unique_lock<std::mutex> lock(mtx);
        ready = true;
        cond.notify_one();
    }

bool done() { return !ready; }

private:
    std::thread t;
    std::atomic<bool> ready, terminate; // What can I do with all these?
    std::mutex mtx;                     //
    std::condition_variable cond;       //
};

int main() {
    worker t;
    t = worker([]() -> void { cout << "Woof" << endl; });
    t.run_once();
    while(!t.done()) ;
    return 0;
}

很抱歉代码的大转储。

推荐答案

我可以通过工人不可复制和不可移动来解决它,并留给用户 worker 将其存储为 unique_ptr 这没有什么错。

I would 'fix' it by just saying worker is noncopyable and nonmoveable and leave it to the user of worker to store it as a unique_ptr if they want to move it around. There's nothing wrong with that at all. It's ordinary, actually.

如果你绝对希望这个类是可移动的,你可以使用Pimpl设计模式:make a Worker :: Impl 拥有 unique_ptr 的嵌套类。 Impl 类将不可复制和不可移动,基本上是您当前的 worker 类。 lambda将有一个指向 Impl 类的指针,而不是 worker 类。 worker 类将不包含除 Impl unique_ptr >和函数,转发到 Impl 类的函数,并且默认的复制和移动ctors /操作符只会正常工作两个类(工人将可复制但不可移动, impl将是不可复制和不可移动的)。

If you absolutely want this class to be movable, you could use the Pimpl design pattern: make a Worker::Impl nested class which worker owns by unique_ptr. The Impl class would be noncopyable and nonmovable and basically be your current worker class. The lambda would have a pointer to the Impl class, not the worker class. The worker class would contain nothing except a unique_ptr to the Impl and functions that forward to the Impl class' functions, and the defaulted copy and move ctors/operators will just work properly for both classes (worker will be copyable but not movable, impl will be noncopyable and nonmovable).

这篇关于移动具有线程作为成员变量的类的操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆