2.1 线程管理基础
每个C++程序至少有一个线程,这个线程运行main函数。你的程序可以增加线程去以其他函数作为进入点。这些函数会同步执行,当程序从main函数中返回的时候,指定的函数也会返回,线程退出。正如你看到的如果你有一个std::thread对象,你可以等待它结束,但是首先你必须启动它,所以让我们看看怎么启动线程吧;
2.1.1 执行一个线程
线程启动通过std::thread对象指定要运行的任务。最简单的事指定一个名字,无参数无返回值的函数。这个函数将在它自己的线程中执行知道返回,线程停止。另一方面,任务可以额外附加一个参数。通过消息系统传递一系列操作,知道当他的信号到达的时候停止。线程做什么从哪儿执行是没有关系的,但是使用c++线程库开始的线程可以归结为一个对象std::thread:
void do_some_work();
std::thread mythread(do_some_work);
这是如此的简单。当然你必须保证引入<thread>头文件,让编译器可以找到这个类。同大多数C++标准库一样,std::thread可以工作在任何可调动的类型上,所以你可以传一个类的实例到thread中:
class background_task
{
public:
void operator()()const
{
do_something();
do_something()else();
}
};
background_task f;
std::thread mythread(f);
在这个例子中,提供的函数被拷贝到线程的存储空间中被调用和执行。知道调用的是副本是非常重要的,否则可能产生不希望的结果。
传递一个临时变量,例如:
std::thread my_thread(background_task());
声明一个单个参数的my_thread函数,返回一个std::thread对象,你可以通过命名你的函数对象去避免这样。例如:
std::thread my_thread((background_task()));
std::thread my_thread{background_task()};
可以使用lambda表达式避免这种情况:
std::thread my_thread([]{do_something();
do_something_else();
});
一旦你开始了你的线程,你必须决定是否等待它结束或者返回。如果在线程销毁钱不做任何处理,你的程序会被终止。因此你应该确保你的线程加入或分离,即使在异常的存在的情况下。记住你必须决定线程对象销毁钱,这个线程可能在你join或detach钱完成,如果你分离它,线程可能会继续执行在线程对象被销毁前。
如果你不等待你的线程完成,你需要确保数据访问时合法的知道你的线程完成它。这不是一个新问题-单线程的时候也不可以访问一个被销毁的对象。
当线程函数中使用指针或者引用只想一个局部变量的时候肯能会碰到这种问题。下面的代码展示了这样一个场景:
struct func
{
int& i;
func(int& i_):i(i_){}
void operator()()
{
for(unsigned j=0; j<1000000;++j)
{
do_something(i);
}
}
}
void oops()
{
int some_local_state = 0;
func my_func(some_local_state);
std::thread my_thread(my_func);
my_thread.detach();
}
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。