转移线程所有权
一. std::thread 实例之间 (t1,t2 和 t3) 转移所有权
- void some_function();
- void some_other_function();
- std::thread t1(some_function); // 1
- std::thread t2=std::move(t1); // 2
- t1=std::thread(some_other_function); // 3
- std::thread t3; // 4
- t3=std::move(t2); // 5
- t1=std::move(t3); // 6 赋值操作将使程序崩溃
当显式使用 std::move() 创建 t2 后2,t1 的所有权就转移给了 t2. 之后, t1 和执行线程已经没有关联了; 执行 some_function 的函数现在与 t2 关联.
然后, 与一个临时 std::thread 对象相关的线程启动了3. 为什么不显式调用 std::move() 转移所有权呢? 因为, 所有者是一个临时对象 -- 移动操作将会隐式的调用.
t3 使用默认构造方式创建4, 与任何执行线程都没有关联. 调用 std::move() 将与 t2 关联线程的所有权转移到 t3 中5.
因为 t2 是一个命名对象, 需要显式的调用 std::move() . 移动操作5完成后, t1 与执行 some_other_function 的线程相关联, t2 与任何线程都无关联, t3 与执行 some_function 的线程相关联.
最后一个移动操作, 将 some_function 线程的所有权转移6给 t1. 不过, t1 已经有了一个关联的线程 (执行 some_other_function 的线程), 所以这里系统直接调用 std::terminate() 终止程序继续运行. 这样做(不抛出异常, std::terminate() 是 noexcept 函数) 是为了保证与 std::thread 的析构函数的行为一致, 进行赋值时也需要满足这些条件(说明: 不能通过赋一个新值给 std::thread 对象的方式来 "丢弃" 一个线程
std::thread 支持移动, 就意味着线程的所有权可以在函数外进行转移. 当所有权可以在函数内部传递, 就允许 std::thread 实例可作为参数进行传递.
二. std::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)); // 产生线程
- }
- std::for_each(threads.begin(),threads.end(),std::mem_fn(&std::thread::join)); // 对每个线程调用 join()
- }
将 std::thread 放入 std::vector 是向线程自动化管理迈出的第一步: 并非为这些线程创建独立的变量, 并且将他们直接加入, 可以把它们当做一个组.
来源: http://www.jianshu.com/p/84493ecee6ae