在“C ++并发操作”一书中有一个例子:
class background_task { public: void operator() () const { do_something(); do_something_else(); } }; background_task f; std::thread my_thread(f);
接下来是文本:“在这种情况下,提供的函数对象被复制到属于新创建的执行线程的存储中并从那里调用。因此,复制行为必须与原始行为等效,否则结果可能不是什么是预期的。“
有人可以向我详细解释这两句话的含义吗?那些可以提供给线程对象的构造函数的其他可调用类型,它们是不是被复制了?如何确保“副本的行为与原始行为等效”或为什么它的行为不相同?谢谢!
该陈述将给定的例子与正常函数void do_some_work();
作为参数传递给std::thread
之前的情况形成鲜明对比。
std::thread my_thread(do_some_work);
函数对象background_task f
应该是可复制的。如果class background_task
由使其不可复制的东西组成,则这是不可能的。例如,如果background_task
有std::mutex
,它将不可复制,因为std::mutex
不可复制或移动。见Demo。
第二件事是,即使background_task
是可复制的,也应确保复制构造函数生成原始的精确副本。不会发生这种情况的一个例子是众所周知的情况,其中类具有原始指针,而复制构造函数不执行深层复制。
可调用的void do_some_work();
也像函数对象一样被复制到线程中,但不会遇到上面提到的问题。
这里没有什么可读的。
必须将可调用的内容复制到线程中,否则调用它将不是线程安全的。
如果可调用的类型具有应该说“意外”的复制语义(想想一个非常奇怪的复制构造函数),那么对于任何试图使用您的代码的人来说,这都是坏消息。
而已!