移动特性说明
C++标准库中有很多资源占有(resource-owning)类型,比如std::ifstream,std::unique_ptr还有std::thread都是可移动,但不可拷贝。
移动拷贝或者移动赋值都使得原有对象对所属资源的控制权发生转移,从对象A转移到对象B,对资源的控制只在对象B中保留。
以下是std::thread线程类的移动特性的声明,支持移动构造和移动对象,但不可拷贝。
//移动构造函数
thread( thread&& other ) noexcept;
//移动对象
thread& operator=( thread&& other ) noexcept;
//复制构造函数被删除
thread(const thread&) = delete;
以下两种情形都将发生线程类对象的移动操作,例如:
//返回thread参数
std::thread get_thread()
{
//方式一:
//return std::thread (do_fun, 100);
//方式二:
std::thread td(do_fun, 100);
return td;
}
//传递thread参数
void move_thread(std::thread td)
{
}
在C++ 11中标准库中,提供了std::move函数用于资源移动操作,这个一般应用于命名类对象std::thread td1
,其函数声明如下:
template< class T >
typename std::remove_reference::type&& move( T&& t ) noexcept;
std::move 用于指示对象 t 可以“被移动”,即允许从 t 到另一对象的有效率的资源传递。
线程移动操作变化说明
当一个std::thread对象执行移动操作后,线程的所有权将发生转移,原有线程对象的相关标识被清空,失去线程的控制权。其原有线程类对象ID变为0,joinable变为为false。
代码说明如下:
void do_fun(int num)
{
++num;
}
int _tmain(int argc, _TCHAR* argv[])
{
int num = 10;
//原有对象
std::thread task(do_fun, num);
std::cout << "before call move task thread id is " << task.get_id() << std::endl;
std::cout << "before call move task thread joinable status is " << task.joinable() << std::endl;
//发生移动操作
std::thread move_task = std::move(task);
std::cout << "\nafter call move task thread id is " << task.get_id() << std::endl;
std::cout << "after call move task thread joinable status is " << task.joinable() << std::endl;
std::cout << "\nmove_task thread id is " << move_task.get_id() << std::endl;
std::cout << "move_task thread joinable status is " << move_task.joinable() << std::endl;
//如果joinable为false, 调用join 程序异常,
//移动后task对象的joinable为false
if (task.joinable())
{
task.join();
std::cout << "call task member function " << std::endl;
}
//如果joinable为false, 调用join 程序异常
if (move_task.joinable())
{
move_task.join();
std::cout << "call move_task member function " << std::endl;
}
}
运行结果:
before call move task thread id is 17512
before call move task thread joinable status is 1
after call move task thread id is 0
after call move task thread joinable status is 0
move_task thread id is 17512
move_task thread joinable status is 1
call move_task member function
下面就利用线程的移动特性,进行量产线程,并等待它们结束。
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()
}