【Boost】boost库中thread多线程详解8——call_once仅运行一次
2016-01-26 14:25
543 查看
还有一个问题没有解决:如何使得初始化工作(比如说构造函数)也是线程安全的。比方说,如果一个引用程序要产生唯一的全局的对象,由于实例化顺序的问题,某个函数会被调用来返回一个静态的对象,它必须保证第一次被调用时就产生这个静态的对象。这里的问题就是如果多个线程同时调用了这个函数,那么这个静态对象的构造函数就会被调用多次,这样错误产生了。解决这个问题的方法就是所谓的“一次实现”(once routine)。“一次实现”在一个应用程序只能执行一次。如果多个线程想同时执行这个操作,那么真正执行的只有一个,而其他线程必须等这个操作结束。为了保证它只被执行一次,这个routine由另一个函数间接的调用,而这个函数传给它一个指针以及一个标志着这个routine是否已经被调用的特殊标志。这个标志是以静态的方式初始化的,这也就保证了它在编译期间就被初始化而不是运行时。因此也就没有多个线程同时将它初始化的问题了。Boost线程库提供了boost::call_once来支持“一次实现”,并且定义了一个标志boost::once_flag及一个初始化这个标志的宏BOOST_ONCE_INIT。List6是一个使用了boost::call_once的例子。其中定义了一个静态的全局整数,初始值为0;还有一个由BOOST_ONCE_INIT初始化的静态boost::once_flag实例。main函数创建了两个线程,它们都想通过传入一个函数调用boost::call_once来初始化这个全局的整数,这个函数是将它加1。main函数等待着两个线程结束,并将最后的结果输出的到std::cout。由最后的结果可以看出这个操作确实只被执行了一次,因为它的值是1。
一个共享资源不得不在某个地方被初始化,并且你希望第一次使用这个资源的线程来完成初始化工作。一个once_flag类型和call_once函数能够保证多个线程不会重复的初始化同一个对象。首先,必须使用BOOST_ONCE_INIT宏来初始化这个once_flag对象。boost::once_flag Conn::init_ = BOOST_ONCE_INIT; 之后调用call_once函数,boost::call_once(Conn::init, Conn::init_); 第一个形参是希望被执行一次的初始化函数的地址。
#include <boost/thread/thread.hpp> #include <boost/thread/once.hpp> #include <iostream> int i = 0; boost::once_flag flag = BOOST_ONCE_INIT; void init() { ++i; } void thread() { boost::call_once(&init, flag); } int main(int argc, char* argv[]) { boost::thread thrd1(&thread); boost::thread thrd2(&thread); thrd1.join(); thrd2.join(); std::cout << i << std::endl; return 0; }
#include <iostream> #include <boost/thread/thread.hpp> #include <boost/thread/once.hpp> // Some sort of connection class that should only be initialized once struct Conn { static void init( ) {++i_;} static boost::once_flag init_; static int i_; // ... }; int Conn::i_ = 0; boost::once_flag Conn::init_ = BOOST_ONCE_INIT; void worker( ) { boost::call_once(Conn::init, Conn::init_); // Do the real work... } Conn c; // You probably don't want to use a global, so see the // next Recipe int main( ) { boost::thread_group grp; for (int i = 0; i < 100; ++i) grp.create_thread(worker); grp.join_all( ); std::cout << c.i_ << '\n';// c.i_ = 1 }
一个共享资源不得不在某个地方被初始化,并且你希望第一次使用这个资源的线程来完成初始化工作。一个once_flag类型和call_once函数能够保证多个线程不会重复的初始化同一个对象。首先,必须使用BOOST_ONCE_INIT宏来初始化这个once_flag对象。boost::once_flag Conn::init_ = BOOST_ONCE_INIT; 之后调用call_once函数,boost::call_once(Conn::init, Conn::init_); 第一个形参是希望被执行一次的初始化函数的地址。
相关文章推荐
- 当当开源sharding-jdbc,轻量级数据库分库分表中间件
- 网页版计算器的实现(js实现计算功能)
- Xcode升级插件失效 | 错误选择了Skip Bundle
- HashMap的扩容
- HDU-1267 下沙的沙子有几粒?
- Insert into select 与create table as的性能测试及create table
- 欢迎使用CSDN-markdown编辑器
- JAVA基础(15) java代码获取当前域名
- countUp
- SQL Server 索引设计指南
- java文件操作解析
- 数组中只出现一次的数字
- poj-2299-Ultra-QuickSort(线段树 || 归并排序)
- 南阳oj 题目44 子串和
- php路由
- FOR XML PATH多行合并到一行
- ZOJ1014
- 运行时动态修复dex
- 利用Canvas实现360度浏览
- 在Ubuntu下编译Assimp库