以线程作为成员变量的 class 的移动操作
Move operations for a class with a thread as member variable
我正在尝试扩展一些人在这里帮助我的东西 所以我的工人 class 可以支持移动构造函数和移动 operator=
,但我遇到了问题我的 class 通过副本(或引用)绑定 this
到线程,因此它可以访问 class 值。其中有几个atomic<bool>
,一个condition_variable
和一个mutex
。
但是当我尝试移动它时,因为线程绑定到另一个条件变量 mutex
和 atomic
s,我对它所做的任何事情都不起作用。我怎样才能解决这个问题?
我是否需要使用更复杂的对象而不是 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_ptr
。 Impl
class 将是不可复制和不可移动的,基本上就是您当前的 worker
class。 lambda 将有一个指向 Impl
class 而不是 worker
class 的指针。 worker
class 除了 Impl
的 unique_ptr
和转发给 Impl
class 函数的函数,以及默认的copy 和 move ctors/operators 将对两个 classes 正常工作(worker 可复制但不可移动,impl 不可复制且不可移动)。
我正在尝试扩展一些人在这里帮助我的东西 operator=
,但我遇到了问题我的 class 通过副本(或引用)绑定 this
到线程,因此它可以访问 class 值。其中有几个atomic<bool>
,一个condition_variable
和一个mutex
。
但是当我尝试移动它时,因为线程绑定到另一个条件变量 mutex
和 atomic
s,我对它所做的任何事情都不起作用。我怎样才能解决这个问题?
我是否需要使用更复杂的对象而不是 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_ptr
。 Impl
class 将是不可复制和不可移动的,基本上就是您当前的 worker
class。 lambda 将有一个指向 Impl
class 而不是 worker
class 的指针。 worker
class 除了 Impl
的 unique_ptr
和转发给 Impl
class 函数的函数,以及默认的copy 和 move ctors/operators 将对两个 classes 正常工作(worker 可复制但不可移动,impl 不可复制且不可移动)。