以线程作为成员变量的 class 的移动操作

Move operations for a class with a thread as member variable

我正在尝试扩展一些人在这里帮助我的东西 所以我的工人 class 可以支持移动构造函数和移动 operator=,但我遇到了问题我的 class 通过副本(或引用)绑定 this 到线程,因此它可以访问 class 值。其中有几个atomic<bool>,一个condition_variable和一个mutex

但是当我尝试移动它时,因为线程绑定到另一个条件变量 mutexatomics,我对它所做的任何事情都不起作用。我怎样才能解决这个问题? 我是否需要使用更复杂的对象而不是 lambda 来移动它,以便线程可以引用它?或者还有其他选择。 一如既往的帮助将不胜感激:)。

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

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;
}

很抱歉大量代码转储。

我会 'fix' 它只是说 worker 是不可复制和不可移动的,如果他们想要的话,将它留给 worker 的用户将其存储为 unique_ptr移动它。这完全没有错。其实很普通。

如果你绝对希望这个 class 是可移动的,你可以使用 Pimpl 设计模式:制作一个 Worker::Impl 嵌套 class,worker 拥有 unique_ptrImpl class 将是不可复制和不可移动的,基本上就是您当前的 worker class。 lambda 将有一个指向 Impl class 而不是 worker class 的指针。 worker class 除了 Implunique_ptr 和转发给 Impl class 函数的函数,以及默认的copy 和 move ctors/operators 将对两个 classes 正常工作(worker 可复制但不可移动,impl 不可复制且不可移动)。