一、thread的使用python
boost的thread包含了线程建立、使用、同步等内容,使用thread须要包含头文件"boost\thread.hpp"。linux
thread中使用了须要编译的thread库,因此还须要添加thread库到项目附加库目录,在linux下连接thread库时还须要使用-lpthread选项来连接posix线程库。c++
定义一个thread对象后,线程就开始执行。thread构造函数的第一个参数是一个函数或函数对象或function对象,剩余参数是传递给执行函数或函数对象的参数, 若是但愿是引用传递的话则须要配合使用ref。多线程
成员函数join()和timed_join()能够用来阻塞等待线程执行结束,其中timed_join()能够指定等待时间。成员函数detach()的功能相似于posix的pthread_detach():建立一个线程后默认的状态是joinable, 若是一个线程结束运行但没有被join,会有一部分资源没有被回收。能够在建立线程后调用detach()将线程执行体分离,这样该线程运行结束后会自动释放全部资源,而没必要使用join来阻塞等待线程结束。调用detach()将线程执行体分离后,成员函数joinable()会返回false,即线程的状态是非状态是非joinable。ide
须要注意的是thread对象时不可拷贝的。函数
#include "boost\thread.hpp" void PrintThreadFunc(const int& n, const string& str) { cout << str << n << endl; } int main() { int n1 = 1; string str1 = "hello"; boost::thread t1(PrintThreadFunc, ref(n1), ref(str1)); int n2 = 2; string str2 = "boost"; function<void()> fun = bind(PrintThreadFunc, ref(n2), ref(str2)); boost::thread t2(fun); t1.timed_join(boost::posix_time::seconds(1)); //最多等待1秒 t2.join(); //一直等待 return 0; }
二、线程的一些操做this
能够调用成员函数get_id()得到线程ID,线程ID提供了比较操做符和流输出操做,所以能够做为标准容器的元素。当一个线程的状态是joinable的,那么能够调用成员函数get_id()得到线程ID,线程ID提供了比较操做符和流输出操做,所以能够做为标准容器的元素。若是调用了成员函数detach()将线程执行体分离,那么get_id()得到的线程ID与静态函数thread::id()的返回值相同。spa
静态函数this_thread::get_id()能够得到当前线程的线程ID。线程
静态函数thread::this_thread::sleep()可让当前线程睡眠一段时间或到指定时间,3d
静态函数thread::hardware_concurrency()能够得到当前CPU的内核数量。
静态函数this_thread::yield()指示当前线程放弃时间片,容许其余线程运行。
boost::this_thread::sleep(boost::posix_time::seconds(2)); //睡眠2秒 cout << boost::this_thread::get_id() << endl; //输出当前线程ID cout << boost::thread::hardware_concurrency() << endl; //输出CPU核心数 boost::this_thread::yield(); //放弃当前CPU时间
c++11中也有对应的操做,eg:
std::this_thread::sleep_for(std::chrono::seconds(5)); //睡眠5秒
std::this_thread::sleep_for(4ms); //睡眠4毫秒,须要引用命名空间:using namespace std::chrono
三、线程中断
thread的成员函数interrupt()设置正在执行的线程被中断,被中断的线程会抛出一个thread_interrupted异常,它不是std::exception或boost::exception的子类。thread_interrupted异常应该在线程执行函数里捕获并处理,以下所示,若是没有捕获处理这个异常,默认的动做是终止线程。
void ThreadFun() try { //函数体 } catch (boost::thread_interrupted&) { //异常处理 }
线程其实不是任意时刻都能被中断的,只有当线程执行到中断点的时候才被中断,thread中的中断点有:thread::join()系列函数、thread::sleep()函数、condition_variable::wait()系列函数、this_thread::interruption_point()函数,其中this_thread::interruption_point()函数表示执行到本函数的时候就能够被中断。
缺省状况下线程都是容许中断的,this_thread::interruption_enabled()函数能够检测当前线程是否容许中断,this_thread::interruption_requested()用来检测当前线程是否被要求中断。this_thread中的disable_interruption类是一个RAII类型的对象,它在构造的时候关闭线程的中断,析构的时候恢复线程的中断状态。
四、线程组
线程组thread_group用于管理一组建立的线程,成员函数create_thread()能够建立thread对象并运行线程,也能够建立thread对象后使用成员函数add_thread()来加入线程组。成员函数create_thread()的声明以下:
template<typename F> thread* create_thread(F threadfunc);
成员函数remove_thread()能够删除线程组里的thread对象,成员函数join_all()用来等待全部的thread对象,成员函数interrupt_all()用来中断全部的thread对象。
使用示例:
boost::thread_group tg; int n1 = 0; tg.create_thread(bind(ThreadFun1, n1, "c++")); int n2 = 0; tg.create_thread(bind(ThreadFun2, n2, "python")); tg.join_all();
五、future
若是想要得到线程函数的返回值,可使用future范式。
六、call_once()
call_once()用来设置在多线程环境下指定的函数只被调用一次。
七、C++11中的线程
#include <thread> void foo(int x) { x = 0; } void bar(int& x) { x = 0; } int main() { int n1 = 50, n2 = 100; std::thread first(foo, n1); std::thread second(bar, ref(n2)); first.join(); //first.detach(); second.join(); //second.detach(); cout << n1 << endl; //n1为50 cout << n2 << endl; //n2为0 return 0; }
须要注意的几点:
①、可执行的thread对象必须在他被销毁以前被主线程join(调用thread对象的join())或者将其设置为 detached(调用thread对象的detach),不然会产生abort。
②、若是使用函数对象做为thread的参数的话,直接传入临时对象会出错,能够定义一个对象传入或者使用lambda表达式:
class CTask { public: void operator()() { int a = 0; } }; //std::thread th1(CTask()); //直接传入临时对象会出错 CTask task; std::thread th1(task); th1.join();
③、传递给线程函数的参数是先保存在于一个中转站中,当函数执行的时候再传给函数的形参,而这个时候传递的参数指向的值颇有可能已经失效,因此,对于线程函数传递的参数应该与形参类型相同,而不是再进行转换:
void task(int& a, string str) { } int iNum = 0; char* pStr = new char[100]; strcpy(pStr, "test"); //std::thread th(task, 5, std::ref(iNum), pStr); //不该该直接传入pStr,防止task中还未对参数str初始化成功pStr已被释放。 std::thread th(task, std::ref(iNum), string(pStr)); //应该传入对应类型 delete[] pStr; th.join();
④、若是线程函数的参数是引用的话传入时还须要使用ref包住传入的参数,不然也是值传递。