假设要写一个在后台启动线程的函数, 想通过新线程返回的所有权去调用这个函数, 而不是等待线程结束再去调用; 或完全与之相反的想法: 创建一个线程, 并在函数中转移所有权,都必须要等待线程结束。 总之, 新线程的所有权都需要转移。这就是移动引入 std::thread 的原因。
C++标准库中有很多资源占有(resource-owning)类型,比如 std::ifstream
, std::unique_ptr
还有 std::thread 都是可移动(movable), 但不可拷贝(not cpoyable)。 这就说明执行线程的所有权可以在 std::thread 实例中移动, 下面将展示一个例子。
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后②, t1的所有权就转移给了t2。 之后, t1和执行线程已经没有关联了; 执行some_function
的函数现在与t2关联。 - 然后, 与一个临时 std::thread 对象相关的线程启动了③。 为什么不显式调用 std::move() 转移所有权呢? 因为, 所有者是一个临时对象——移动操作将会隐式的调用。
- t3使用默认构造方式创建④, 与任何执行线程都没有关联。 调用 std::move() 将与t2关联线程的所有权转移到t3中⑤。 因为t2是一个命名对象, 需要显式的调用 std::move()。
- 最后一个移动操作, 将
some_function
线程的所有权转移⑥给t1。 不过, t1已经有了一个关联的线程(执行some_other_function
的线程), 所以这里系统直接调用std::terminate()
终止程序继续运行。 终止操作将调用 std::thread 的析构函数, 销毁所有对象。
std::thread 对象的容器, 如果这个容器是移动敏感的(比如, 标准中的 std::vector<> ), 那么移动操作同样适用于这些容器。
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,move,t2,t1,线程,所有权,转移 From: https://www.cnblogs.com/love-9/p/18093133