作者:冯刚 2011-8-4
1 背景
BOOST是由c++标准化委员会成员参与开发的c++标准的准官方库,他是C++标准库的发动机。下一代C++标准C++0x的标准库很多来自于boost。Boost库覆盖了广泛的领域,从数学库到智能指针,从模板元编程库到预处理器库及语法词法分析,从线程到lambda表达式,等等。所有Boost库都具有宽松的许可证,确保库可以被自由使用于商用软件。
2 功能 2.1 概况
Boost库涵盖了很广泛的领域,下面就常用的功能像智能指针,正则表达式,函数对象bind和function, 线程和线程池,时间日期,多索引容器,哈希容器,bimap,日志,内存池,模板元编程,循环缓冲区,tuple, 观察者模式signal2,网络通讯asio做一些介绍。
2.2 功能
2.2.1 智能指针 2.2.1.1 概论
smart pointers(智能指针)是存储“指向动态分配(在堆上)的对象的指
针”的对象。他们的行为很像 C++ 的内建指针,只是它们可以在适当的时候自动删除它们所指向的对象。智能指针在面对异常时有非常显著的作用,它们可以确保动态分配对象的完全析构。它们还可以用于跟踪多主人共享的动态分配对象。
在概念上,智能指针可以看作拥有它所指向的对象,并因此在对象不再需要时负责将它删除。
智能指针库提供了六个智能指针类模板: scoped_ptr 2.2.1.2 智能指针shared_ptr shared_ptr 类模板存储一个指向动态分配对象(一般是用 C++ new-expression 生成的)的指针。在最后一个 shared_ptr 所指向的对象被销毁或重置时,要保证它所指向的对象被删除。 每一个 shared_ptr 都符合 C++ 标准库的 CopyConstructible 和 Assignable 的必要条件,并因此能够用于标准库容器。因为提供了比较操作,因此 shared_ptr 可以和标准库中的关联式容器一起工作。 通常,一个 shared_ptr 不能正确地持有一个指向动态分配的数组的指针。关于那种用法请参见 shared_array。 因为在实现中使用了引用计数,shared_ptr实例的循环引用不会被回收。例如,如果 main() 持有一个指向 A 的 shared_ptr, A 又直接或间接持有一个指回 A 的 shared_ptr,A 的使用计数是 2。最初的 shared_ptr 析构后将导致一个使用计数为 1 的 A 被悬挂。使用 weak_ptr 以“打破循环”。 这个类模板被 T 参数化,T 是被指向的对象的类型。shared_ptr 和它的大多数成员函数对于 T 没什么要求,允许它是一个不完整类型,或者为 void。对 T 有附加要求的成员函数 (constructors, reset) 都明确地记录在下面。 只要 T* 能被隐式地转换到 U*,则 shared_ptr shared_ptr。特别是,shared_ptr 惯用手法 由于智能指针是线程安全的,建议在代码里只为一个对象生成单一的 shared_ptr,在多线程环境中传递参数时使用weak_ptr,这样当shared_ptr被析构,weak_ptr也会得到通知,变为无效,这样可以有效地防止野指针,同时也防止了潜在的循环引用,无法释放对象的问题。 shared_ptr spA = shared_ptr(new A); int func(weak_ptr wpA) { If(!wpA.expired()) { } else { } } func(spA); //智能指针已被其他线程释放 //正常处理逻辑 shared_ptr spA = wpA.lock(); //Use spA 2.2.1.3 智能指针weak_ptr 简介 weak_ptr是Boost智能指针shared_ptr的一个重要伙伴。它允许打破循环依赖。另外,它还可以处理一个非常常见的问题—悬空指针。当销毁最后一个智能指针 shared_ptr,它会释放掉共享的资源。通过使用智能指针weak_ptr,这方面的信息会传播给所有观察该共享资源的智能指针weak_ptr,通过weak_ptr可以知道该共享资源已经释放,这意味着不会发生无意间访问无效指针的情形。这就是观察者模式的一个特例,也就是说,当销毁资源的时候,就会通知所有对资源感兴趣的weak_ptr,通过调用weak_ptr.expired(),当返回值为true时,就表示该共享资源已经释放了。 weak_ptr 类模板存储一个引向已被 shared_ptr 管理的对象的 \"weak reference\"(弱引用)。为了访问这个对象,一个 weak_ptr 可以利用 shared_ptr 的构造函数或成员函数 lock 转换为 shared_ptr。当最后一个指向对象的 shared_ptr 消失,而对象也被删除后,从一个引向已被删除对象的 weak_ptr 实例获取 shared_ptr 的企图就会失败:构造函数会抛出一个 boost::bad_weak_ptr 类型的异常,而 weak_ptr::lock 会返回一个 empty shared_ptr。 每一个 weak_ptr 都符合 C++ 标准库的 CopyConstructible 和 Assignable 的必要条件,并因此能够用于标准库容器。因为提供了比较操作,因此 weak_ptr 可以和标准库中的关联式容器一起工作。 weak_ptr 的操作绝不会抛出异常。 这个类模板被 T 参数化,T 是被指向的对象的类型。 相对于 shared_ptr,weak_ptr 提供了一个非常有限的操作子集,因为在多线程程序中访问它所存储的指针是非常危险的,甚至有时在一个单线程程序中也是不安全的(也就是说,它可能引起未定义行为)。姑且假设 weak_ptr 有一个返回 raw pointer(裸指针)的 get 成员函数,考虑下面这个无辜的代码片段: shared_ptr // some time later if(int * r = q.get()) { // use *r } 设想在 if 之后,但是又恰恰在 r 被使用之前,另一个线程执行了语句 p.reset()。这样 r 就成了一个 dangling pointer(悬挂指针)。 解决这个问题的方案是从 q 创建一个临时的 shared_ptr: shared_ptr // some time later if(shared_ptr // use *r } 这样,r 就持有一个引向 q 所指向的对象的引用。即使在其它线程中执行了 p.reset(),那个对象也会继续活着,直到 r 离开作用域或者被 reset。通过获得一个指向这个对象的 shared_ptr,我们可以有效地保住它不被析构。 2.2.2 正则表达式 xpressive 是一个先进的、面向对象的、用于C++的正则表达式模板库。正则表达式可以以字符串方式编写并在运行期分析,也可以以表达式模板方式编写并在编译期分析。正则表达式可以相互引用,或者递归引用其本身,你就可以用它们来构建任意复杂的语法。它与Boost.Regex库的区别就是无需编译,全模板库。 如果你要在C++中处理文本,通常你有两个不相交的选项:正则表达式引擎或语法分析生成器。正则表达式引擎(如 Boost.Regex)更为强大和灵活;文本的模式以字符串方式表示,可以在运行期指定。但是,这意味着语法错误同样要到运行期才能被检测。另外,正则表达式不适合于高级的文本处理任务,如匹配平衡的、嵌套的标签。那些任务传统上都是由语法分析生成器(如 Spirit 语法分析器框架)来处理的。这些工具更为强大,但不够灵活。它们通常不允许你随时随意地修改你的语法规则。此外,它们不具备正则表达式的完全回溯语义,对于某些类型的模式来说,这样对作者更具有挑战性。 将这两种方法无缝地集合到一起,在C++的文本处理世界中占据了独特的优势。通过 xpressive,你可以选择更象使用 Boost.Regex 那样去使用它,将正则表达式表示为字符串。或者你也可以象使用 Spirit 那样使用它,将你的 regexes 写为C++表达式,获得一种专用于文本处理的嵌入式语言所带来的所有好处。更重要的是,你可以混用这两种方式,从而获得两者的好处,对于那些要静态绑定的正则表达式编写正则表达式语法 -- 由编译器进行硬编码和语法检查 -- 其它的则动态绑定并在运行期指定。这些正则表达式可以相互递归地引用,在以前的正则表达式不能进行模式匹配的字符串中进行模式匹配。 Xpressive 是一个只含头文件的模板库,这意味着你不需要修改你的构建脚本或链接任何独立的lib文件就可以使用它。你所要做的就是 #include 表 28.1. xpressive的工具箱 Tool 工具 basic_regex<> match_results<>, sub_match<> regex_match() regex_search() regex_replace() regex_iterator<> regex_token_iterator<> Description 说明 含有一个已编译的正则表达式。 basic_regex<> 是xpressive之中最重要的类型。你用xpressive做的任何事情都要从创建一个类型为 basic_regex<> 的对象开始。 match_results<> 含有 regex_match() 或 regex_search() 操作的结果。它就象一个存有 sub_match<> 对象的向量。一个 sub_match<> 对象含有一个已标记的子表达式(在Perl中又称为后向引用)。基本上,它只是一个迭代器对,代表了已标记子表达式的开始和结束。 检查一个字符串是否匹配一个regex。regex_match() 要成功,必须是整个字符串从头到尾匹配regex。如果你给了 regex_match() 一个 match_results<>,那么它会将所有找到的带标记子表达式写入其中。 查找一个字符串,以发现其中匹配regex的子字符串。regex_search() 将尝试在字符串的每个位置查找匹配,从头部开始,当找到一个匹配或者整个字符串找完时停止。使用 regex_match() 时,如果你给了 regex_search() 一个 match_results<>,那么它会将所有找到的带标记子表达式写入其中。 给定一个输入字符串,一个regex和一个替代字符串,regex_replace() 通过将输入字符串中与regex相匹配的部分替换为替代字符串来构建一个新的字符串。替代字符串可以含有对带标记子表达式的引用。 一个与STL兼容的迭代器,可以很方便地找到在一个字符串中与某个regex匹配的所有地方。解引用一个 regex_iterator<> 会返回一个 match_results<>。递增一个 regex_iterator<> 可以找出下一个匹配。 类似于 regex_iterator<>,除了一点,解引用一个 regex_token_iterator<> 会返回一 Tool 工具 Description 说明 个字符串。缺省地,它返回与regex匹配的整个子字符串,不过它也可以被配置为每次返回任一个或整个带标记子表达式,或者甚至是不匹配 regex的部分字符串。 一个用于 basic_regex<> 对象的工厂。它将一个字符串\"编译\"为正则表达式。通常,你不需要直接关心 regex_compiler<>,因为 basic_regex<> 类有一个工厂方法,其内部使用了 regex_compiler<>。不过,如果你需要做一些花哨的东西,如创建一个带有不同 std::locale 的 basic_regex<> 对象,你就需要显式使用 regex_compiler<> 了。 regex_compiler<> 现在你应该对xpressive所提供的工具有了一些了解,你可以通过回答以下两个问题来找到合适的工具: 1. 你要用哪种类型的迭代器来遍历你的数据? 2. 你要对你的数据做什么操作? 弄明白你的迭代器类型 在xpressive中的多数类都是根据迭代器类型参数化的模板类。xpressive定义了一些常用的typedefs来让你可以更容易地选择合适的类型。你可以用下表基于你的迭代器类型来找到正确的类型。 下表 为 xpressive Typedefs 与迭代器类型 std::string::cchar const onst_iterator * sregex cregex std::wstring::wchar_t const_iterator const * wsregex wcregex basic_regex<> match_results<> smatch cmatch wsmatch wcmatch std::string::cchar const onst_iterator * sregex_compiler sregex_iterator cregex_compiler cregex_iterator cregex_token_iterator std::wstring::wchar_t const_iterator const * wsregex_compiler wsregex_iterator wsregex_token_iterator wcregex_compiler wcregex_iterator wcregex_token_iterator regex_compiler<> regex_iterator<> regex_tokensregex_token_iterator<> _iterator 你要留意系统的命名习惯。这些类型经常要一起使用,所以命名习惯可以帮助你一致地使用它们。例如,如果你有一个 sregex,你就应该使用 smatch。 如果你用的不是以上四种迭代器类型之一,那么你可以直接用模板并指定你的迭代器类型。 示例 以下你将看到六个完整的示例程序。 检查整个字符串是否匹配一个regex 这是来自于\"简介\"一节中的示例。为便于查看,在此重复。 #include #include std::string hello( \"hello world!\" ); sregex rex = sregex::compile( \"(\\\\w+) (\\\\w+)!\" ); smatch what; if( regex_match( hello, what, rex ) ) { std::cout << what[0] << '\\n'; // whole match 整个匹配 std::cout << what[1] << '\\n'; // first capture 第一次捕获 std::cout << what[2] << '\\n'; // second capture 第二次捕获 } return 0; } 程序输出如下: hello world! hello world 检查一个字符串是否包含匹配某个regex的子串 请留意在这个例子中,我们是如何使用定制的 mark_tags 来使得匹配的模式更可读。我们可以在稍后使用 mark_tags 来对 match_results<> 进行索引访问。 #include #include char const *str = \"I was born on 5/30/1973 at 7am.\"; // 以名字定义一些定制的 mark_tags,比 s1, s2 等更有意义。 mark_tag day(1), month(2), year(3), delim(4); //该regex查找一个日期 cregex date = (month= repeat<1,2>(_d)) // 查找月份... >> (delim= (set= '/','-')) // 后跟一个分隔符... >> (day= repeat<1,2>(_d)) >> delim // 和一个日期再跟一个分隔符... >> (year= repeat<1,2>(_d >> _d)); //和年份。 cmatch what; if( regex_search( str, what, date ) ) { std::cout << what[0] << '\\n'; // whole match 全匹配 std::cout << what[day] << '\\n'; // the day 日期 std::cout << what[month] << '\\n'; // the month 月份 std::cout << what[year] << '\\n'; // the year 年份 std::cout << what[delim] << '\\n'; // the delimiter 分隔符 } return 0; } This program outputs the following: 程序输出如下: 5/30/1973 30 5 1973 / 替换匹配某个regex的所有子串 以下程序在一个字符串中查找日期并用伪-HTML标记它们。 #include #include std::string str( \"I was born on 5/30/1973 at 7am.\" ); // 基本上与上一个例子中的regex相同,但用的是动态regex sregex date = sregex::compile( \"(\\\\d{1,2})([/-])(\\\\d{1,2})\\\\2((?:\\\\d{2}){1,2})\" ); // 和在Perl中一样,$& 是指向匹配该regex的子串的引用 std::string format( \" 程序输出如下: I was born on 查找匹配某个regex的所有子串并每次一个地分步处理它们 以下程序在一个宽字符串中查找单词。它使用 wsregex_iterator。注意,对 wsregex_iterator 的解引用将产生一个 wsmatch 对象。 #include #include int main() { std::wstring str( L\"This is his face.\" ); //查找一个完整的单词 wsregex token = +alnum; wsregex_iterator cur( str.begin(), str.end(), token ); wsregex_iterator end; for( ; cur != end; ++cur ) { wsmatch const &what = *cur; std::wcout << what[0] << L'\\n'; } return 0; } 程序输出如下: This is his face 将字符串分拆为匹配某个regex的记号 以下程序在字符串中查找比赛时间,并且先显示分钟数再显示秒数。它使用 regex_token_iterator<>. #include #include std::string str( \"Eric: 4:40, Karl: 3:35, Francesca: 2:32\" ); //查找比赛时间 sregex time = sregex::compile( \"(\\\\d):(\\\\d\\\\d)\" ); // 对于每个匹配,记号迭代器首先取出第一个被标记的子表达式的值,然后是第二个子表达式的值 int const subs[] = { 1, 2 }; sregex_token_iterator cur( str.begin(), str.end(), time, subs ); sregex_token_iterator end; for( ; cur != end; ++cur ) { std::cout << *cur << '\\n'; } return 0; } This program outputs the following: 程序输出如下: 4 40 3 35 2 32 用一个regex作为分隔符分拆字符串 以下程序接受一些带有html标记的文本,去掉其中的标记。它使用一个regex来匹配HTML标签,并用一个 regex_token_iterator<> 返回字符串中不匹配该regex的其余部分。 #include #include std::string str( \"Now // find a HTML tag 查找一个HTML标签 sregex html = '<' >> optional('/') >> +_w >> '>'; // 以下的 -1 指示记号迭代器显示字符串中不匹配正则表达式的部分。 sregex_token_iterator cur( str.begin(), str.end(), html, -1 ); sregex_token_iterator end; for( ; cur != end; ++cur ) { std::cout << '{' << *cur << '}'; } std::cout << '\\n'; return 0; } 程序输出如下: {Now }{is the time }{for all good men}{ to come to the aid of their}{ country.} 显示嵌套结果组成的树 以下是一个辅助类,示范了如何显示由嵌套结果组成的树: //以缩入方式将嵌套结果输出至 std::cout struct output_nested_results { int tabs_; output_nested_results( int tabs = 0 ) : tabs_( tabs ) { } template< typename BidiIterT > void operator ()( match_results< BidiIterT > const &what ) const { //首先进行缩入 typedef typename std::iterator_traits< BidiIterT >::value_type char_type; char_type space_ch = char_type(' '); std::fill_n( std::ostream_iterator std::cout << what[0] << '\\n'; //输出嵌套的匹配 std::for_each( what.nested_results().begin(), what.nested_results().end(), output_nested_results( tabs_ + 1 ) ); } }; 2.2.3 Bind 目的 boost::bind 是标准函数 std::bind1st 和 std::bind2nd 的泛化。它支持任意的函数对象,函数,函数指针,和成员函数指针,它还能将任何参数绑定为一个特定的值,或者将输入的参数发送到任意的位置。bind 对函数对象没有任何要求,特别是,它不需要 result_type,first_argument_type 和 second_argument_type 这样的标准 typedefs。 int f(int a, int b) { return a + b; } int g(int a, int b, int c) { return a + b + c; } bind(f, 1, 2) 会产生一个“无参数”函数对象,它不需要参数并返回 f(1, 2)。同样,bind(g, 1, 2, 3)() 等价于 g(1, 2, 3)。 有选择性地只绑定一部分参数也是有可能的。bind(f, _1, 5)(x) 等价于 f(x, 5),这里,_1 是一个占位符参数,它的含义是“用第一个输入参数取代”。 bind 能够处理带有两个以上参数的函数,而且它的参数取代机制更为直观: bind(f, _2, _1)(x, y); // f(y, x) bind(g, _1, 9, _1)(x); // g(x, 9, x) bind(g, _3, _3, _3)(x, y, z); // g(z, z, z) bind(g, _1, _1, _1)(x, y, z); // g(x, x, x) 注意,最后一个示例中,由 bind(g, _1, _1, _1) 生成的函数对象不包含对第一个参数以外的任何参数的引用,但是它仍然能使用一个以上的参数。所有多余的参数被悄悄地忽略,就像在第三个示例中,第一和第二个参数被忽略。 bind 持有的参数被返回的函数对象拷贝并内部持有。例如,在下面的代码中: int i = 5; bind(f, i, _1); 一个 i 的值的拷贝被存储于函数对象中。boost::ref 和 boost::cref 可用于让函数对象存储一个引用而不是拷贝: int i = 5; bind(f, ref(i), _1); bind(f, cref(42), _1); (和函数对象一起使用 bind) bind 并不限于函数,它可以接受任何函数对象。通常情况下,生成的函数对象的 operator() 的返回类型必须显式指定(没有 typeof 操作符,返回类型无法推导): struct F { int operator()(int a, int b) { return a - b; } bool operator()(long a, long b) { return a == b; } }; F f; int x = 104; bind 有些编译器遇到 bind 但是要注意,这种可选语法只是作为一个 workaround 提供。它不是接口的一部分。 当函数对象暴露了一个名为 result_type 的内嵌类型时,显式返回类型可以被省略: int x = 8; bind(std::less // x < 9 【注意:这种省略返回类型的能力并非在所有的编译器上都可用。】 缺省情况下,bind 为提供的函数对象做出一份拷贝。boost::ref 和 boost::cref 可用于让它存储这个函数对象的引用,而非拷贝。当函数对象是不可拷贝的,拷贝代价高昂,或者包含状态时是很有用的,当然,在这种情况下,要求程序员确保这个函数对象在使用期间不能被销毁。 struct F2 { int s; typedef void result_type; void operator()( int x ) { s += x; } }; F2 f2 = { 0 }; int a[] = { 1, 2, 3 }; std::for_each( a, a+3, bind( ref(f2), _1 ) ); assert( f2.s == 6 ); (和成员指针一起使用 bind) 成员函数的指针和数据成员的指针不是函数对象,因为它们不支持 operator()。为了方便起见,bind 接受成员指针作为它的第一个参数,而它的行为就像使用 boost::mem_fn 将成员指针转换成一个函数对象一样。换句话说,当 R 是 X::f 的返回类型(作为成员函数)或成员本身的类型(作为数据成员)时,表达式 bind(&X::f, args) 与 bind 【注意:mem_fn 创建的函数对象可以接受一个对象的指针,引用或智能指针作为它的第一个参数,更多的信息,参见 mem_fn 文档。】 示例: struct X { bool f(int a); }; X x; shared_ptr int i = 5; bind(&X::f, ref(x), _1)(i); bind(&X::f, &x, _1)(i); bind(&X::f, x, _1)(i); bind(&X::f, p, _1)(i); // x.f(i) //(&x)->f(i) // (internal copy of x).f(i) // (internal copy of p)->f(i) 最后两个示例的有趣之处在于它们生成“自包含”的函数对象。bind(&X::f, x, _1) 存储 x 的一个拷贝。bind(&X::f, p, _1) 存储 p 的一个拷贝,而且因为 p 是一个 boost::shared_ptr,这个函数对象保存一个属于它自己的 X 的实例的引用,而且当 p 离开它的作用域或者被 reset() 之后,这个引用依然保持有效。 (为函数组合使用嵌套的 binds) 传给 bind 的某些参数可以嵌套 bind 表达式自身: bind(f, bind(g, _1))(x); // f(g(x)) 当函数对象被调用的时候,如果没有指定顺序,内部 bind 表达式先于外部 bind 表达式被求值,在外部 bind 表达式被求值的时候,用内部表达式的求值结果取代它们的占位符的位置。在上面的示例中,当用参数列表 (x) 调用那个函数对象的时候,bind(g, _1)(x) 首先被求值,生成 g(x),然后 bind(f, g(x))(x) 被求值,生成最终结果 f(g(x))。 bind 的这个特性可被用来执行函数组合。参见示例 bind_as_compose.cpp,示范如何用 bind 达到与 Boost.Compose 类似的功能。 注意第一个参数——被绑定函数对象——是不被求值的,即使它是一个由 bind 生成的函数对象或一个占位符参数,所以下面的示例不会如你所愿地工作: typedef void (*pf)(int); std::vector std::for_each(v.begin(), v.end(), bind(_1, 5)); 你所要的效果,可以通过将一个辅助函数对象 apply 用作它的第一个参数而获得,作为一个函数对象,它可以支撑它的参数列表。为了方便起见,在 boost/bind/apply.hpp 头文件中提供了一个 apply 的实现。下面是一个前面的示例的修改版本: typedef void (*pf)(int); std::vector std::for_each(v.begin(), v.end(), bind(apply 头文件 boost/bind/protect.hpp 包含一个 protect 的实现。要在求值中保护一个 bind 函数对象,使用 protect(bind(f, ...))。 (重载的操作符(Boost 1.33 新增)) 为了方便起见,由 bind 生成的函数对象重载了 logical not(逻辑非)操作符 ! 和关系操作符 ==, !=, <, <=, >, >=, &&, ||。 如果 logical_not 是一个持有一个参数 x 并返回 !x 的函数对象,则 !bind(f, ...) 等价于 bind( logical_not(), bind(f, ...) )。 如果 op 是一个关系或逻辑操作符,并且 relation 是一个持有两个参数 a 和 b 并返回 a op b 的函数对象,则 bind(f, ...) op x 等价于 bind( relation(), bind(f, ...), x )。 这实际上意味着你可以方便地对 bind 的结果求非: std::remove_if( first, last, !bind( &X::visible, _1 ) ); // remove invisible objects 以及方便地将 bind 的结果和一个值进行比较: std::find_if( first, last, bind( &X::name, _1 ) == \"Peter\" ); std::find_if( first, last, bind( &X::name, _1 ) == \"Peter\" || bind( &X::name, _1 ) == \"Paul\" ); 和一个占位符进行比较: bind( &X::name, _1 ) == _2 或者和另一个 bind 表达式进行比较: std::sort( first, last, bind( &X::name, _1 ) < bind( &X::name, _2 ) ); // sort by name 示例 (和 Boost.Function 一起使用 bind) class button { public: boost::function }; class player { public: void play(); void stop(); }; button playButton, stopButton; player thePlayer; void connect() { playButton.onClick = boost::bind(&player::play, &thePlayer); stopButton.onClick = boost::bind(&player::stop, &thePlayer); } 2.2.4 线程库 2.2.4.1 线程管理 2.2.4.1.1 创建线程 Class Param { Int value; } Shared_ptr spParam = new shared_ptr< Param > (new Param); Class A { Int Run(weak_ptr< Param > param); } Shared_ptr spA = new shared_ptr (new A); boost::shared_ptr boost::thread(boost::bind(&A::Run ,spA, weak_ptr< Param >(spParam)))); 2.2.4.1.2 等待线程退出 thread->join(); boost::system_time xt=delay(3); bool const joined= thread->timed_join(xt); thread ->timed_join(boost::posix_time::seconds(3)); 2.2.4.1.3 线程中断 thread ->interrupt(); 2.2.4.1.4 线程休眠 boost::this_thread::sleep(boost::posix_time::milliseconds(10)); 2.2.4.1.5 获取线程ID thread::id get_id() const; 返回值: 如果*this 标识一个线程执行体, 返回有效线程标识( boost::thread::id。 否则返回空的 线程标识(default-constructed boost::thread::id)。 抛出: 无 thread->get_id(); 2.2.4.1.6 线程退出的处理 void exit_func(int exitcode) { } boost::this_thread::at_thread_exit(boost::bind(exit_func,0)); 2.2.4.2 线程池 线程池的种类 先进先出队列线程池 typedef thread_pool 后进先出队列线程池 typedef thread_pool 优先级队列线程池 typedef thread_pool 示例 typedef fifo_pool pool; //创建线程池 boost::threadpool::pool pool; pool.size_controller().resize(10); //调度线程池 //这样调度 boost::threadpool::future pool.schedule(boost::bind(func,err)); 或那样调度 packaged_task packaged_task fut->wait(); 或者定时等待 boost::xtime xt; boost::xtime_get(&xt, boost::TIME_UTC); io_ fut .timed_wait(xt); xt.sec += 30; xt.nsec += ns; 2.2.4.3 同步处理 2.2.4.3.1 互斥量 互斥量对象简化了线程间数据竟态保护和数据同步。一个线程通过一个锁定函数取得一个互斥量的所有权,通过一个对应的解锁函数释放所有权。互斥量可以是支持递归所有权的或非递归所有权的, 也可以同时属于多个线程。 Boost.Thread 库提供递归和非递归互斥量, 支持排他型的所有权和共享所有权(multiple-reader / single-writer)。 所有权概念 Boost.Thread库支持四种基本的所有权概念: Lockable, TimedLockable, SharedLockable 和UpgradeLockable。每种互斥量依据自己的目标实现一种或多种概 念。 Lockable 概念 void lock() bool try_lock() void unlock() 实现 Lockable 概念需要提供下面的成员函数: void lock(); bool try_lock(); void unlock(); 通过 函数lock()或函数try_lock() 获取的所有权需要通过 unlock()来释放。 TimedLockable 概念 TimedLockable concept 概念细化了Lockable concept概念,支持尝试获取所有权时超时放弃。 实现TimedLockable concept 概念的类型除了需要实现 Lockable concept概念。 还需要提供下面的成员函数: bool timed_lock(boost::system_time const& abs_time); template 通过 函数timed_lock() 获取的所有权需要通过 unlock()来释放。 bool timed_lock(boost::system_time const& abs_time) 效果: 当前线程尝试取得该互斥量所有权。 线程阻塞直到它获得所有权, 或等待超过指定的时间点。如果等待时间点已过, 函数的行为和 try_lock()一样。 返回: 如果取得所有权返回true, 否则返回false。 后置条件: 如果返回 true, 当前线程拥有该互斥量。 抛出: 如果出错抛出boost::thread_resource_error异常。 template 效果: 同 timed_lock(boost::get_system_time()+rel_time)。 SharedLockable 概念 SharedLockable concept 细化了TimedLockable concept允许共享所有权 ( shared ownership)和排他型所有权(exclusive ownership)。适用于标准的 multiple-reader / single-write模型: 通常一个线程可以获取排他型所有权, 此时其他线程不能获取到排他型所有权和共享型所有权, 相反的, 多个线程可以同时获得共享所有权。 如果一个类型要实现SharedLockable concept 概念, 除了需要满足TimedLockable concept 概念要求, 还需要提供下面的成员函数: void lock_shared(); bool try_lock_shared(); bool unlock_shared(); bool timed_lock_shared(boost::system_time const& abs_time); 通过 函数 lock_shared(), try_lock_shared() 或 timed_lock_shared() 获取的所有权需要通过unlock_shared()来释放。 void lock_shared() 效果: 当前线程阻塞直到取得互斥量的共享所有权。 后置条件: 当前线程取得互斥量的共享所有权。 抛出: 如果出错抛出boost::thread_resource_error异常。 bool try_lock_shared() 效果: 当前线程尝试取得该互斥量的共享所有权,线程不阻塞。 返回: 如果取得互斥量的共享所有权返回true, 否则返回false。 后置条件: 如果返回 true, 当前线程取得互斥量的共享所有权。 抛出: 如果出错抛出boost::thread_resource_error异常。 bool timed_lock_shared(boost::system_time const& abs_time) 效果: 当前线程尝试取得该互斥量的共享所有权。 线程阻塞直到它获得所有权, 或等待超过指定的时间点。如果等待时间点已过, 函数的行为和 try_lock_shared()一样& nbsp;。 返回: 如果取得互斥量的共享所有权返回true, 否则返回false。。 后置条件: 如果返回 true, 当前线程取得互斥量的共享所有权。 抛出: 如果出错抛出boost::thread_resource_error异常。 void unlock_shared() 前置条件: 当前线程拥有互斥量的共享所有权。 效果: 释放当前线程拥有的互斥量共享所有权。 后置条件: 当前线程不在拥有该互斥量共享所有权。 抛出: 无 UpgradeLockable 概念 UpgradeLockable concept 是SharedLockable concept的细化,特点在于允许所有权升级到独占状态。这是对共享所有权支持的multiple-reader / single-write模型的一个扩展:一个线程可以拥有upgradable ownership而同时其他线程拥有共享所有权 该线程可以在任何时候试图升级其所有权为独占式所有,如果此时没有其他线程拥有共享所有权,升级立即完成, 该线程就会拥有独占所有权, 这个所有权需要通过 unlock()来释放, 就像这个所有权是通过lock()取得一样。 如果该线程试图升级到独占所有时,其他线程拥有对应的共享所有权, 升级会失败,该线程阻塞直到其获得独占所有权。 UpgradeLockable concept中的所有权也可以降级: 独占式所有权可以降级为可升级所有权或者共享所有权,可升级所有权可以降级为一般共享所有权。 如果一个类型要实现 UpgradeLockable concept概念,除了需要实现 SharedLockable concept概念, 它还需要提供下面的成员函数: void lock_upgrade(); bool unlock_upgrade(); void unlock_upgrade_and_lock(); void unlock_and_lock_upgrade(); void unlock_upgrade_and_lock_shared(); 通过函数lock_upgrade() 取得的所有权需要通过函数 unlock_upgrade()来释放 。如果所有权类型通过函数unlock_xxx_and_lock_yyy()改变 , 所有权必须通过新所有权对应的释放函数来释放。 void lock_upgrade() 效果: 当前线程阻塞直到它获得可升级所有权。 后置条件: 当前线程取得该对象的可升级所有权。 抛出: 如果出错抛出boost::thread_resource_error异常。 void unlock_upgrade() 前置条件: 当前线程拥有该对象的可升级所有权。 效果: 释放当前线程拥有的该对象的可升级所有权。 后置条件: 当前线程不在拥有该对象的可升级所有权。 抛出: 无 void unlock_upgrade_and_lock() 前置条件: 当前线程拥有该对象的可升级所有权。 效果: 当前线程自动释放拥有的该对象可升级所有权,并试图取得该对象的独占所有权, 线程阻塞直到其获得独占所有权。 后置条件: 当前线程拥有该对象的独占所有权。 抛出: 无 void unlock_upgrade_and_lock_shared() 前置条件: 当前线程拥有该对象的可升级所有权。 效果: 当前线程自动释放拥有的该对象可升级所有权,取得共享所有权,该函数会立即返回。 后置条件: 当前线程拥有该对象的共享所有权。 抛出: 无 void unlock_and_lock_upgrade() 前置条件: 当前线程拥有该对象的独占所有权。 。 效果: 当前线程自动释放拥有的该对象独占级所有权,取得可升级所有权,该函数会立即返回。 后置条件: 当前线程自动拥有该对象可升级所有权。 抛出: 无 锁定类型(Lock Types) lock_guard unique_lock shared_lock upgrade_lock upgrade_to_unique_lock scoped_try_lock lock_guard lock_guard(Lockable & m) lock_guard(Lockable & m,boost::adopt_lock_t) ~lock_guard() template explicit lock_guard(Lockable& m_); lock_guard(Lockable& m_,boost::adopt_lock_t); ~lock_guard(); }; #include boost::lock_guard 非常简单: 构造函数传入一个可锁定对象,构造函数取得可锁定对象的所有权。 析构时释放所有权。 这样为可锁定对象提供了一个 RAII 风格的外观, 方便实现异常安全的锁定和解锁。 额外的, 构造函数the lock_guard(Lockable & m,boost::adopt_lock_t) 允许boost::lock_guard对象取得当前线程已拥有锁定的所有权,也就是不改变当前已拥有的所有权。 const defer_lock_t defer_lock={}; const try_to_lock_t try_to_lock={}; const adopt_lock_t adopt_lock={}; unique_lock #include template unique_lock(); explicit unique_lock(Lockable& m_); unique_lock(Lockable& m_,adopt_lock_t); unique_lock(Lockable& m_,defer_lock_t); unique_lock(Lockable& m_,try_to_lock_t); unique_lock(Lockable& m_,system_time const& target_time); ~unique_lock(); unique_lock(detail::thread_move_t operator detail::thread_move_t unique_lock& operator=(detail::thread_move_t void swap(unique_lock& other); void swap(detail::thread_move_t void lock(); bool try_lock(); template bool timed_lock(TimeDuration const& relative_time); bool timed_lock(::boost::system_time const& absolute_time); void unlock(); bool owns_lock() const; operator unspecified-bool-type() const; bool operator!() const; Lockable* mutex() const; Lockable* release(); }; boost::unique_lock比 boost::lock_guard复杂许多: 不仅是它提供RAII风格的外观, 它也允许推迟获得锁定, 直到lock() 函数显式调用, 或者支持非阻塞 方式获得锁定, 或者是支持超时锁定。 最后, 析构函数在可锁定对象被其锁定的情况下调用unlock() 函数。 boost::unique_lock特化实现了 TimedLockable concept 概念(e.g. boost::unique_lock 如果函数mutex() 返回指向的 m 指针并且owns_lock() 返回 true,该 boost::unique_lock实例拥有一个可锁定对象的锁定状态 。如果该种实例被销毁, 析构函数会调用函数mutex()->unlock()。 boost::unique_lock的成员函数不是线程安全的。 特别的, boost::unique_lock是针对单一线程对可锁定对象所有权建立模型的, 这样一个对象的成员函数(包含构造析构函数)必须在同一个线程内调用。基本上用于栈变量,不建议用于堆变量。 shared_lock #include template shared_lock(); explicit shared_lock(Lockable& m_); shared_lock(Lockable& m_,adopt_lock_t); shared_lock(Lockable& m_,defer_lock_t); shared_lock(Lockable& m_,try_to_lock_t); shared_lock(Lockable& m_,system_time const& target_time); shared_lock(detail::thread_move_t ~shared_lock(); operator detail::thread_move_t shared_lock& operator=(detail::thread_move_t void lock(); bool try_lock(); bool timed_lock(boost::system_time const& target_time); void unlock(); operator unspecified-bool-type() const; bool operator!() const; bool owns_lock() const; }; boost::shared_lock 对Lockable concept建模 , 但是不仅支持可锁定对象, 还支持共享锁定获取。 和 boost::unique_lock一样,不仅提供RAII风格的外观, 它也允许推迟获得锁定, 直到lock() 函数显式调用, 或者支持非阻塞方式获得锁定, 或者是支持超时锁定。 最后, 析构函数在可锁定对象被其锁定的情况下调用unlock() 函数。 如果函数mutex() 返回指向的 m 指针并且owns_lock() 返回 true,该 boost::shared_lock实例拥有一个可锁定对象的锁定状态 。如果该种实例被销毁, 析构函数会调用函数mutex()->unlock()。 boost::shared_lock的成员函数不是线程安全的。 特别 的, boost::shared_lock是针对单一线程对可锁定对象所有权建立模型的, 这样一个对象的成员函数(包含构造析构函数)必须在同一个线程内调用。 upgrade_lock #include template explicit upgrade_lock(Lockable& m_); upgrade_lock(detail::thread_move_t ~upgrade_lock(); operator detail::thread_move_t upgrade_lock& operator=(detail::thread_move_t void swap(upgrade_lock& other); void lock(); void unlock(); operator unspecified-bool-type() const; bool operator!() const; bool owns_lock() const; }; 和boost::unique_lock一样,boost::upgrade_lock对可锁定概念建模,但是不仅限于可锁定对提供的独占锁定,还支持可升级锁定。 和 boost::unique_lock一样,不仅提供RAII风格的外观, 它也允许推迟获得锁定, 直到lock() 函数显式调用, 或者支持非阻塞方式获得锁定, 或者是支持超时锁定。 最后, 析构函数在可锁定对象被其锁定的情况下调用unlock() 函数。 如果函数mutex() 返回指向的 m 指针并且owns_lock() 返回 true,该 boost::upgrade_lock实例拥有一个可锁定对象的锁定状态 。如果该种实例被销毁, 析构函数会调用函数mutex()->unlock()。 boost::upgrade_lock的成员函数不是线程安全的。 特别的, boost::upgrade_lock是针对单一线程对可锁定对象所有权建立模型的, 这样一个对象的成员函数(包含构造析构函数)必须在同一个线程内调用。 upgrade_to_unique_lock #include template explicit upgrade_to_unique_lock(upgrade_lock ~upgrade_to_unique_lock(); upgrade_to_unique_lock(detail::thread_move_t upgrade_to_unique_lock& operator=(detail::thread_move_t void swap(upgrade_to_unique_lock& other); operator unspecified-bool-type() const; bool operator!() const; bool owns_lock() const; }; boost::upgrade_to_unique_lock 允许临时从可升级锁定升级到独占锁定,如果传递boost::upgrade_lock对象的引用给构造函数,该对象将升级到独占所有权,当这个对象销毁时,可锁定对象恢复为可升级锁定。 scoped_try_lock class MutexType::scoped_try_lock { private: MutexType::scoped_try_lock(MutexType::scoped_try_lock MutexType::scoped_try_lock(); explicit MutexType::scoped_try_lock(MutexType& m); MutexType::scoped_try_lock(MutexType& m_,adopt_lock_t); MutexType::scoped_try_lock(MutexType& m_,defer_lock_t); MutexType::scoped_try_lock(MutexType& m_,try_to_lock_t); MutexType::scoped_try_lock(MutexType::scoped_try_lock void swap(MutexType::scoped_try_lock&& other); void lock(); bool try_lock(); void unlock(); bool owns_lock() const; MutexType* mutex() const; MutexType* release(); bool operator!() const; typedef unspecified-bool-type bool_type; operator bool_type() const; }; 成员类型 scoped_try_lock 为已定义的不同的 MutexType 提供了一个类型定义。其所有的函数与boost::unique_lock 锁定函数 lock(Lockable1,Lockable2,...) lock(begin,end) try_lock(Lockable1,Lockable2,...) try_lock(begin,end) 自由函数 lock(Lockable1,Lockable2,...) template template template void lock(Lockable1& l1,Lockable2& l2,Lockable3& l3,Lockable4& l4); template void lock(Lockable1& l1,Lockable2& l2,Lockable3& l3,Lockable4& l4,Lockable5& l5); 效果: 锁定参数提供的 Lockable& nbsp;对象,并避免死锁。 该函数在多个线程并发调用锁定同一组互斥量(或其他可锁定对象)是安全的,并且不用指定锁定顺序,也不用担心死锁。如果函数在锁定对象时抛出异常,那么在函数退出前,该函数此次调用已锁定的对象也会被释放。 抛出: 对可锁定对象加锁时可能抛出的异常。 后置条件: 参数中提供的可锁定对象都被加锁。 自由函数lock(begin,end) template void lock(ForwardIterator begin,ForwardIterator end); 前置条件: ForwardIterator 的value_type需要实现 Lockable concept。 效果: 锁定迭代区间的 Lockable对象,并避免死锁。 该函数在多个线程并发调用锁定同一组互斥量(或其他可锁定对象)是安全的,并且不用指定锁定顺序,也不用担心死锁。如果函数在锁定对象时抛出异常,那么在函数退出前,该函数此次调用已锁定的对象也会被释放。 抛出: 对可锁定对象加锁时可能抛出的异常。 后置条件: 迭代区间中的可锁定对象都被加锁。 自由函数 try_lock(Lockable1,Lockable2,。..) template template template template int try_lock(Lockable1& l1,Lockable2& l2,Lockable3& l3,Lockable4& l4,Lockable5& l5); 效果: 对参数中的可锁定对象依次调用 try_lock() 函数, 如果有一个try_lock() 调用返回 false,那么已经获得的锁定就会被释放,并返回这个锁定失败对象在参数中的序号(以 0为基数)。 如果有一个 try_lock() 调用抛出异常, 那么已经获得的锁定会在函数退出前释放。 返回: 如果所有对象都成功加锁,返回-1, 否则返回第一个失败对象的序号(以0为基数)。 抛出: 调用try_lock()可能抛出的异常。 后置条件: 如果函数返回 -1,& nbsp;所有对象都被加锁,否则参数中的对象都不会加锁。 自由函数 try_lock(begin,end) template ForwardIterator try_lock(ForwardIterator begin,ForwardIterator end); 前置条件: ForwardIterator 的value_type需要实现 Lockable concept。 效果: 通过函数 try_lock()锁定迭代区间的 Lockable对象, 如果有一个try_lock() 调用返回 false,那么已经获得的锁定就会被释放,并返回这个锁定失败对象对应的迭代器。 如果有一个 try_lock() 调用抛出异常, 那么已经获得的锁定会在函数退出前释放。 返回: 如果所有对象都成功加锁,返回end,否则返回第一个失败对象对应的迭代器。 抛出: 调用try_lock()可能抛出的异常。 后置条件: 如果函数返回end , 迭代区间内的对象都被加锁,否则迭代区间内的对象都不会加锁。 互斥量的种类 boost::mutex实现Lockable concept ,提供一个独占式的互斥量。 对于一个实例最多允许一个线程拥有其锁定 。支持函数lock(), try_lock() 和 unlock() 并发调用。 #include class mutex: boost::noncopyable { public: mutex(); ~mutex(); void lock(); bool try_lock(); void unlock(); typedef platform-specific-type native_handle_type; native_handle_type native_handle(); typedef unique_lock typedef unspecified-type scoped_try_lock; }; boost::timed_mutex 实现TimedLockable concept ,提供一个独占式的互斥量。 对于一个实例最多允许一个线程拥有其锁定 。支持函数lock(), try_lock() ,timed_lock()和 unlock() 并发调用。 #include class timed_mutex: boost::noncopyable { public: timed_mutex(); ~timed_mutex(); void lock(); void unlock(); bool try_lock(); bool timed_lock(system_time const & abs_time); template bool timed_lock(TimeDuration const & relative_time); typedef platform-specific-type native_handle_type; native_handle_type native_handle(); typedef unique_lock boost::recursive_mutex;实现了 Lockable concept,提供一个递归式的互斥量 。 对于一个实例最多允许一个线程拥有其锁定 。支持函数lock(), try_lock() 和 unlock() 并发调用。如果一个线程已经锁定一个boost::recursive_mutex实例, 那么这个线程可以多次通过lock() 或 try_lock()锁定这个实例,针对每一次成功的锁定动作,需要调用unlock()来接触锁定。 #include class recursive_mutex: boost::noncopyable { public: recursive_mutex(); ~recursive_mutex(); void lock(); bool try_lock(); void unlock(); typedef platform-specific-type native_handle_type; native_handle_type native_handle(); typedef unique_lock boost::recursive_timed_mutex 实现TimedLockable concept ,提供一个递归式的 互斥量。 对于一个实例最多允许一个线程拥有其锁定 。支持函数lock(), try_lock() ,timed_lock()和 unlock() 并发调用。如果一个线程已经锁定一个boost::recursive_timed_mutex实例,那么这个线程可以多次通过lock() ,timed_lock()或 try_lock()锁定这个实例,针对每一次成功的锁定动作,需要调用unlock()来接触锁定。 #include class recursive_timed_mutex: boost::noncopyable { public: recursive_timed_mutex(); ~recursive_timed_mutex(); void lock(); bool try_lock(); void unlock(); bool timed_lock(system_time const & abs_time); template bool timed_lock(TimeDuration const & relative_time); typedef platform-specific-type native_handle_type; native_handle_type native_handle(); typedef unique_lock boost::shared_mutex提供了一个multiple-reader / single-writer互斥量,实现了 UpgradeLockable concept.。 允许并发调用函数 lock(), try_lock(), timed_lock(), lock_shared(), try_lock_shared() 和 timed_lock_shared()。 #include class shared_mutex { public: shared_mutex(); ~shared_mutex(); void lock_shared(); bool try_lock_shared(); bool timed_lock_shared(system_time const& timeout); void unlock_shared(); void lock(); bool try_lock(); bool timed_lock(system_time const& timeout); void unlock(); void lock_upgrade(); void unlock_upgrade(); void unlock_upgrade_and_lock(); void unlock_and_lock_upgrade(); void unlock_and_lock_shared(); void unlock_upgrade_and_lock_shared(); }; 2.2.4.3.2 概述 Condition 变量 类型 condition_variable 和 condition_variable_any 提供一个种机制,一个线程可以等待另外一个线程内某个事件发生的通知。 通常的应用模式是一个线程锁定一个互斥量,然后通过函数wait等待一个condition_variable 或 condition_variable_any实例,当线程从wait 函数激活时 , 检查特定的条件是否满足,如果满足,线程继续执行;如果不满足,线程继续等待。最简单的情况下,这个条件只是一个布尔变量。 boost::condition_variable cond; boost::mutex mut; bool data_ready; void process_data(); void wait_for_data_to_process() { boost::unique_lock cond.wait(lock); } process_data(); } 请注意 lock 对象会传递给 wait函数: wait 函数会自动将线程添加到等待条件变量的线程集合中,并且解锁传递进来的互斥量。当线程被唤醒,函数退出前互斥量会再次被锁定。这样允许其他线程获取互斥量来更新共享的数据,确保条件变量关联的数据被正确同步。 同时,另外的线程将这个条件置为true,and 然后对条件变量调用函数 notify_one 或 notify_all来唤醒等待该条件变量的一个线程或多个线程 。 void retrieve_data(); void prepare_data(); void prepare_data_for_processing() { retrieve_data(); prepare_data(); { boost::lock_guard cond.notify_one(); } 注意,同一个互斥量在共享数据被更新前被锁定,但是这个互斥量锁定范围不需要包含函数notify_one. 调用。 这个例子使用一个condition_variable 对象,如果换成condition_variable_any对象也是同样适用。 condition_variable_any 更加通用,支持和其他类型的互斥量和锁定类型,而condition_variable 要求传递给函数wait的是 boost::unique_lock condition_variable 可以做适当的优化; condition_variable_any 类型的实现比 condition_variable复杂许多。 condition_variable #include namespace boost { class condition_variable { public: condition_variable(); ~condition_variable(); void notify_one(); void notify_all(); void wait(boost::unique_lock template void wait(boost::unique_lock bool timed_wait(boost::unique_lock template bool timed_wait(boost::unique_lock template bool timed_wait(boost::unique_lock template bool timed_wait(boost::unique_lock // backwards compatibility bool timed_wait(boost::unique_lock template bool timed_wait(boost::unique_lock condition_variable() 效果: 创建一个条件变量对象。 抛出: 如果出现错误,抛出异常boost::thread_resource_error。 ~condition_variable() 前置条件: 所有等待这个条件变量的线程得到通知(通过调用函数notify_one 或notify_all, 尽管不是每个独立的函数调用wait或 timed_wait 都返回)。 效果: 销毁条件变量。 抛出: 无。 void notify_one() 效果: 如果有线程当前因为等待这个条件变量(wait 或timed_wait)阻塞,这个函数调用会解除一个线程的阻塞状态。 抛出: 无。 void notify_all() 效果: 如果有线程当前因为等待这个条件变量(wait 或timed_wait)阻塞,这个函数调用会解除所有这些线程的阻塞状态。 抛出: 无。 void wait(boost::unique_lock 前置条件: lock对象被当前线程锁定, 或者被等待该状态变量的其他线程锁定,或者所有在等待该状态变量的线程传递的lock对象指向相同的互斥量。 效果: 自动调用 lock.unlock()并且阻塞当前线程。 线程在函数notify_one()或notify_all调用通知后解除阻塞状态,然后线程在 wait函数退出前调用lock.lock() 来加锁。如果这个函数因为异常退出,退出前也会调用lock.lock()。 后置条件: 当前线程锁定lock。 抛出: 如果出错抛出异常boost::thread_resource_error。如果对线程执行体关联的boost::thread对象调用函数interrupt(), 抛出boost::thread_interrupted异常。 template 效果: while(!pred()) { wait(lock); } bool timed_wait(boost::unique_lock 前置条件: lock对象被当前线程锁定, 或者被等待该状态变量的其他线程锁定,或者所有在等待该状态变量的线程传递的lock对象指向相同的互斥量。 效果: 自动调用 lock.unlock()并且阻塞当前线程。 线程在函数notify_one()或notify_all调用通知后解除阻塞状态,另外在boost::get_system_time()得到的时间超过abs_time 后线 程也会解除阻塞, 然后线程在 wait函数退出前调用lock.lock() 来加锁。如果这个函 数因为异常退出,退出前也会调用lock.lock()。 返回: 如果函数因为指定的时间到达而退出,返回false,否则 true。 后置条件: 当前线程锁定lock。 如果出错抛出异常boost::thread_resource_error。如果对线程执行体关联的boost::thread对象调用函数interrupt(), 抛出boost::thread_interrupted异常。 template