2.3 转移线程的所有权
std::move转移线程的所有权
与std::ifstream 与 std::unique_ptr一样,std::thread也是可移动的,而非可复制的。这意味着一个特定的执行线程的所有权可以在std::thread实例之间移动,但是,在任意时刻,只有一个std::thread对象与某个特定的线程相关联。
void some_function(); void some_other_function(); int main() { std::thread t1(some_function); // 启动一个新线程运行some_function,并与t1相关联 std::thread t2 = std::move(t1); // 调用std::move()来显示转移线程所有权 /* 此时: * t1不再拥有相关联的执行线程 * t2与运行some_function的线程相关联 */ t1 = std::thread(some_other_function); // 启动一个新线程执行some_other_function,并与一个临时的std::thread对象相关联,再将所有权转移到t1; std::thread t3; // t3为默认构造的std::thread对象,没有与任何执行线程相关联 t3 = std::move(t2); // 将与t2相关联的线程的所有权转移到t3 /* 此时: * t1运行some_other_function的线程现在相关联 * t2不再拥有相关联的执行线程 * t3与运行some_function的线程现在相关联 */ t1 = std::move(t3); // 错误:欲将与t3相关联的线程的所有权转移到t1,但是t1已经有了一个相关联的线程(运行着some_other_function),所以会调用std::terminate()来终止程序 return 0; }
修改后:
void some_function(); void some_other_function(); int main() { std::thread t1(some_function); std::thread t2 = std::move(t1); t1 = std::thread(some_other_function); std::thread t3; t3 = std::move(t2); t1.detach(); // 调用detach()后,t1不再与任何线程相关联 t1 = std::move(t3); // 正确:将与t3相关联的线程的所有权转移到t1 t1.join(); return 0; }
从函数返回std::thread
void some_function(); std::thread f() { return std::thread(some_function); } void some_other_function(); std::thread g() { std::thread t(some_other_function); return t; }
也可以把线程所有权转移到函数中,但是函数只能以值的形式接受std::thread的实例作为其中一个参数
void f2(std::thread t); void g2() { // 调用方式1 void some_function(); f2(std::thread(some_function)); // 调用方式2 std::thread t(some_function); f2(std::move(t)); }
自定义线程管理类
void do_something(int value); void do_something_in_current_thread(); class scoped_thread { public: explicit scoped_thread(std::thread t_) : t(std::move(t_)) { if (!t.joinable())// 判断线程是否可结合 throw std::logic_error("No thread");// 引发异常 } ~scoped_thread() { t.join();// 等待线程结束 } scoped_thread(scoped_thread const&) = delete; scoped_thread& operator=(scoped_thread const&) = delete; private: std::thread t; }; struct func { int& i; func(int& i_):i(i_){} void operator()() { for (unsigned j = 0; j < 1000000; j++) { do_something(i); } } }; void f() { int some_local_state; scoped_thread t(std::thread(func(some_local_state)));// 将运行函数func(some_local_state)的线程所有权转移至scoped_thread对象t内 do_something_in_current_thread(); }
生成一批线程并等待它们完成
void do_work(unsigned id); void f() { std::vector<std::thread> threads; for (unsigned i = 0; i < 20; i++) { threads.push_back(std::thread(do_work, i)); // 生成线程 } // 轮流在每个线程上调用join() std::for_each(threads.begin(), threads.end(), std::mem_fn(&std::thread::join)); }