boost muti-thread
背景
• 今天互联网应用服务程序普遍使用多线程来提高与多客户链接时的效率;为了达到最大的吞吐量,事务服务器在单独的线程上运行服务程序;
GUI应用程序将那些费时,复杂的处理以线程的形式单独运行,以此来保证用户界面能够及时响应用户的操作。这样使用多线程的例子还有很多。
• 跨平台
创建线程
• 头文件
namespace boost {
class thread;
class thread_group;
}
• thread():构造一个表示当前执行线程的线程对象
• explicit thread(const boost::function0& threadfunc)
注:boost::function0可以简单看为:一个无返回(返回void),无参数的函数。这里的函数也可以是类重载operator()构成的函数。
第一种方式:最简单方法
• #include
• #include
•
• void hello()
• {
• std::cout <<
• "Hello world, I''m a thread!"
• << std::endl;
• }
•
• int main(int argc, char* argv[])
• {
• boost::thread thrd(&hello);
• thrd.join();
• return 0;
• }
第二种方式:复杂类型对象作为参数来创建线程
• #include
• #include
• #include
•
• boost::mutex io_mutex;
•
• struct count
• {
• count(int id) : id(id) { }
•
• void operator()()
• {
• for (int i = 0; i < 10; ++i)
• {
• boost::mutex::scoped_lock
• lock(io_mutex);
• std::cout << id << ": "
• << i << std::endl;
• }
• }
•
• int id;
• };
•
• int main(int argc, char* argv[])
• {
• boost::thread thrd1(count(1));
• boost::thread thrd2(count(2));
• thrd1.join();
• thrd2.join();
• return 0;
• }
第三种方式:在类内部创建线程
• (1)类内部静态方法启动线程
• #include
• #include
• class HelloWorld
• {
• public:
• static void hello()
• {
• std::cout <<
• "Hello world, I''m a thread!"
• << std::endl;
• }
• static void start()
• {
•
• boost::thread thrd( hello );
• thrd.join();
• }
•
• };
• int main(int argc, char* argv[])
• {
• HelloWorld::start();
•
• return 0;
• }
• 在这里start()和hello()方法都必须是static方法。
• (2)如果要求start()和hello()方法不能是静态方法则采用下面的方法创建线程:
• #include
• #include
• #include
• class HelloWorld
• {
• public:
• void hello()
• {
• std::cout <<
• "Hello world, I''m a thread!"
• << std::endl;
• }
• void start()
• {
• boost::function0< void> f = boost::bind(&HelloWorld::hello,this);
• boost::thread thrd( f );
• thrd.join();
• }
•
• };
• int main(int argc, char* argv[])
• {
• HelloWorld hello;
• hello.start();
• return 0;
• }
• (3)在Singleton模式内部创建线程:
• #include
• #include
• #include
• class HelloWorld
• {
• public:
• void hello()
• {
• std::cout <<
• "Hello world, I''m a thread!"
• << std::endl;
• }
• static void start()
• {
• boost::thread thrd( boost::bind
• (&HelloWorld::hello,&HelloWorld::getInstance() ) ) ;
• thrd.join();
• }
• static HelloWorld& getInstance()
• {
• if ( !instance )
• instance = new HelloWorld;
• return *instance;
• }
• private:
• HelloWorld(){}
• static HelloWorld* instance;
•
• };
• HelloWorld* HelloWorld::instance = 0;
• int main(int argc, char* argv[])
• {
• HelloWorld::start();
• return 0;
• }
第四种方法:用类内部函数在类外部创建线程
• #include
• #include
• #include
• #include
• class HelloWorld
• {
• public:
• void hello(const std::string& str)
• {
• std::cout <
• }
• };
•
• int main(int argc, char* argv[])
• {
• HelloWorld obj;
• boost::thread thrd( boost::bind(&HelloWorld::hello,&obj,"Hello
• world, I''m a thread!" ) ) ;
• thrd.join();
• return 0;
• }
如果线程需要绑定的函数有参数则需要使用boost::bind。比如想使用 boost::thread创建一个线程来执行函数:void f(int i),
如果这样写:boost::thread thrd(f)是不对的,因为thread构造函数声明接受的是一个没有参数且返回类型为void的型别,而且
不提供参数i的值f也无法运行,这时就可以写:boost::thread thrd(boost::bind(f,1))。涉及到有参函数的绑定问题基本上都
是boost::thread、boost::function、boost::bind结合起来使用。
互斥体
• 一个互斥体一次只允许一个线程访问共享区。当一个线程想要访问共享区时,首先要做的就是锁住(lock)互斥体。
• Boost线程库支持两大类互斥体,包括简单互斥体(simple mutex)和递归互斥体(recursive mutex)。
有了递归互斥体,单个线程就可以对互斥体多次上锁,当然也必须解锁同样次数来保证其他线程可以对这个互斥体上锁。
• Boost线程库提供的互斥体类型:
boost::mutex,
boost::try_mutex,
boost::timed_mutex,
boost::recursive_mutex,
boost::recursive_try_mutex,
boost::recursive_timed_mutex,
boost::shared_mutex
• mutex类采用Scope Lock模式实现互斥体的上锁和解锁。即构造函数对互斥体加锁,析构函数对互斥体解锁。
• 对应现有的几个mutex导入了scoped_lock,scoped_try_lock,scoped_timed_lock.
• scoped系列的特色就是析构时解锁,默认构造时加锁,这就很好的确定在某个作用域下某线程独占某段代码。
mutex+scoped_lock
• #include
• #include
• #include
• #include
• boost::mutex io_mutex;
• void count(int id)
• {
• for (int i = 0; i < 10; ++i)
• {
• boost::mutex::scoped_lock lock(io_mutex);
• std::cout << id << ": " << i << std::endl;
• }
• }
• int main(int argc, char* argv[])
• {
• boost::thread thrd1(boost::bind(&count, 1));
• boost::thread thrd2(boost::bind(&count, 2));
• thrd1.join();
• thrd2.join();
• return 0;
• }
try_mutex+scoped_try_lock
• void loop(void)
• {
• bool running = true;
• while (running)
• {
• static boost::try_mutex iomutex;
• {
• boost::try_mutex::scoped_try_lock lock(iomutex);//锁定mutex
• if (lock.owns_lock())
• {
• std::cout << "Get lock." << std::endl;
• }
• else
• {
• // To do
• std::cout << "Not get lock." << std::endl;
• boost::thread::yield(); //释放控制权
• continue;
• }
• } //lock析构,iomutex解锁
• }
• }
timed_mutex+scoped_timed_mutex
• void loop(void)
• {
• bool running = true;
• while (running)
• {
• typedef boost::timed_mutex MUTEX;
• typedef MUTEX::scoped_timed_lock LOCK;
• static MUTEX iomutex;
• {
• boost::xtime xt;
• boost::xtime_get(&xt,boost::TIME_UTC);
• xt.sec += 1; //超时时间秒
• LOCK lock(iomutex, xt); //锁定mutex
• if (lock.owns_lock())
• {
• std::cout << "Get lock." << std::endl;
• }
• else
• {
• std::cout << "Not get lock." << std::endl;
• boost::thread::yield(); //释放控制权
• }
• //::sleep(10000); //长时间
• } //lock析构,iomutex解锁
• //::sleep(250);
• }
• }
shared_mutex
• 应用boost::thread的shared_mutex实现singled_write/multi_read的简单例子
• #include
• #include
• #include
• using namespace std;
• using namespace boost;
• boost::shared_mutex shr_mutex;
• /// 这个是辅助类,能够保证log_info被完整的输出
• class safe_log {
• public:
• static void log(const std::string& log_info) {
• boost::mutex::scoped_lock lock(log_mutex);
• cout << log_info << endl;
• }
• private:
• static boost::mutex log_mutex;
• };
• boost::mutex safe_log::log_mutex;
• void write_process() {
• shr_mutex.lock();
• safe_log::log("begin of write_process");
• safe_log::log("end of write_process");
• shr_mutex.unlock();
• }
• void read_process() {
• shr_mutex.lock_shared();
• safe_log::log("begin of read_process");
• safe_log::log("end of read_process");
• shr_mutex.unlock_shared();
• }
• int main() {
• thread_group threads;
• for (int i = 0; i < 10; ++ i) {
• threads.create_thread(&write_process);
• threads.create_thread(&read_process);
• }
• threads.join_all();
• ::system("PAUSE");
• return 0;
• }
条件变量
• 有的时候仅仅依靠锁住共享资源来使用它是不够的。有时候共享资源只有某些状态的时候才能够使用。
比方说,某个线程如果要从堆栈中读取数据,那么如果栈中没有数据就必须等待数据被压栈。这种情
况下的同步使用互斥体是不够的。另一种同步的方式--条件变量,就可以使用在这种情况下。
• boost::condition
typedef condition_variable_any condition;
void wait(unique_lock& m);
• boost::condition_variable
template
void wait(lock_type& m);
• #include
• #include
• #include
• #include
• const int BUF_SIZE = 10;
• const int ITERS = 100;
• boost::mutex io_mutex;
• class buffer
• {
• public:
• typedef boost::mutex::scoped_lock scoped_lock;
• buffer()
• : p(0), c(0), full(0)
• {
• }
• void put(int m)
• {
• scoped_lock lock(mutex);
• if (full == BUF_SIZE)
• {
• {
• boost::mutex::scoped_lock lock(io_mutex);
• std::cout << "Buffer is full. Waiting..." << std::endl;
• }
• while (full == BUF_SIZE)
• cond.wait(lock);
• }
• buf[p] = m;
• p = (p+1) % BUF_SIZE;
• ++full;
• cond.notify_one();
• }
• int get()
• {
• scoped_lock lk(mutex);
• if (full == 0)
• {
• {
• boost::mutex::scoped_lock lock(io_mutex);
• std::cout << "Buffer is empty. Waiting..." << std::endl;
• }
• while (full == 0)
• cond.wait(lk);
• }
• int i = buf[c];
• c = (c+1) % BUF_SIZE;
• --full;
• cond.notify_one();
• return i;
• }
• private:
• boost::mutex mutex;
• boost::condition cond;
• unsigned int p, c, full;
• int buf[BUF_SIZE];
• };
• buffer buf;
• void writer()
• {
• for (int n = 0; n < ITERS; ++n)
• {
• {
• boost::mutex::scoped_lock lock(io_mutex);
• std::cout << "sending: " << n << std::endl;
• }
• buf.put(n);
• }
• }
• void reader()
• {
• for (int x = 0; x < ITERS; ++x)
• {
• int n = buf.get();
• {
• boost::mutex::scoped_lock lock(io_mutex);
• std::cout << "received: " << n << std::endl;
• }
• }
• }
• int main(int argc, char* argv[])
• {
• boost::thread thrd1(&reader);
• boost::thread thrd2(&writer);
• thrd1.join();
• thrd2.join();
• return 0;
• }
线程局部存储
• 函数的不可重入。
• Boost线程库提供了智能指针boost::thread_specific_ptr来访问本地存储线程(thread local storage)。
• #include
• #include
• #include
• #include
• boost::mutex io_mutex;
• boost::thread_specific_ptr ptr;
• struct count
• {
• count(int id) : id(id) { }
• void operator()()
• {
• if (ptr.get() == 0)
• ptr.reset(new int(0));
• for (int i = 0; i < 10; ++i)
• {
• (*ptr)++; // 往自己的线程上加
• boost::mutex::scoped_lock lock(io_mutex);
• std::cout << id << ": " << *ptr << std::endl;
• }
• }
• int id;
• };
• int main(int argc, char* argv[])
• {
• boost::thread thrd1(count(1));
• boost::thread thrd2(count(2));
• thrd1.join();
• thrd2.join();
• return 0;
• }
仅运行一次的例程
• 如何使得初始化工作(比如说构造函数)也是线程安全的。
• “一次实现”(once routine)。“一次实现”在一个应用程序只能执行一次。
• Boost线程库提供了boost::call_once来支持“一次实现”,并且定义了一个标志boost::once_flag及一个初始化这个标志的宏 BOOST_ONCE_INIT。
• #include
• #include
• #include
• 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;
• }
Boost线程库的未来
• Boost线程库正在计划加入一些新特性。其中包括boost::read_write_mutex,它可以让多个线程同时从共享区中读取数据,
但是一次只可能有一个线程向共享区写入数据;boost::thread_barrier,它使得一组线程处于等待状态,知道所有得线程
都都进入了屏障区;boost::thread_pool,他允许执行一些小的routine而不必每一都要创建或是销毁一个线程。
• Boost线程库已经作为标准中的类库技术报告中的附件提交给C++标准委员会,它的出现也为下一版C++标准吹响了第一声号角。
委员会成员对 Boost线程库的初稿给予了很高的评价,当然他们还会考虑其他的多线程库。他们对在C++标准中加入对多线程的
支持非常感兴趣。从这一点上也可以看出,多线程在C++中的前途一片光明。
boost muti-thread的更多相关文章
- boost:thread使用实例
/************************************************************************/ /*功能描述: boost thread使用实例 ...
- boost之thread
1.boost里的thread创建之后会立即启动. 代码示例: #include <iostream> #include <string> #include <vecto ...
- boost库thread.hpp编译警告honored已修复
请浏览:https://svn.boost.org/trac/boost/ticket/7874 #7874: compile warning: thread.hpp:342: warning: ty ...
- 关于boost的thread的mutex与lock的问题
妈的,看了好久的相关的知识,感觉终于自己有点明白了,我一定要记下来啊,相关的知识呀.... 1, 也可以看一下boost的线程指南:http://wenku.baidu.com/link?url=E_ ...
- 【boost】MFC dll中使用boost thread的问题
项目需要,在MFC dll中使用了boost thread(<boost/thread.hpp>),LoadLibraryEx的时候出现断言错误,去掉thread库引用后断言消失. 百度g ...
- Boost Thread学习笔记二
除了thread,boost种:boost::mutexboost::try_mutexboost::timed_mutexboost::recursive_mutexboost::recursive ...
- boost thread 在非正常退出时 内存泄露问题
在使用boost的thread库的时候,如果主程序退出,thread创建的线程不做任何处理,则会出现内存泄露. 解决方法: 在主线程退出时,对所有thread使用interrupt()命令,然后主程序 ...
- gcc boost版本冲突解决日记
问题背景 项目在Ubuntu10 64位 boost 1.55,boost采用的是项目内包含相对目录的形式部署 项目采用了 -Wall -Wextra -Werror -Wconversion 最高的 ...
- boost库(条件变量)
1相关理念 (1)类名 条件变量和互斥变量都是boost库中被封装的类. (2)条件变量 条件变量是thread库提供的一种等待线程同步的机制,可实现线程间的通信,它必须与互斥量配合使用,等待另一个线 ...
- Using Boost Libraries in Windows Store and Phone Applications
Using Boost Libraries in Windows Store and Phone Applications RATE THIS Steven Gates 18 Jul 2014 5:3 ...
随机推荐
- linq to sql 增删改查
ORM<Object Relation Mapping> Linq To Sql: 一.建立Linq To Sql 类 : 理解上下文类: Linq To Sql 类名+context 利 ...
- 如果AlertView输入框为空,则禁止点击确定按钮
//UIAlertView的代理方法(创建UIAlertView之后,copy此代理方法即可) - (BOOL)alertViewShouldEnableFirstOtherButton:(UIAle ...
- Quartz.Net使用
相关的Quartz的Demo https://yunpan.cn/cY3GZGcyTSQxu 访问密码 8b60 官方的写的也挺仔细的.http://www.quartz-scheduler.net ...
- 【转】PS学堂之一:展示一下自己做的圆形印章
共分七个步骤: 1.点击文件--新建,新建一个500×500像素,背景为透明的文件,选择RGB颜色. 2.把前景色和文字颜色设置为正红(R为255,G和B为0). 3.在视图下拉菜单中选择标尺,将横. ...
- 递归小Demo
public class demo5 { public static void main(String[] args) { //初始值为100 int n = 100; ...
- sql语句使用游标修改表中数据
declare @a varchar(),@b varchar() declare user_cursor cursor for select a,b from tableA tab open use ...
- asp结合ajax中文乱码问题
XMLHttpRequest 在w3c标准中这样提到: 如果响应包含了为响应体指定字符编码的头部,就使用该编码.否则,假定使用 Unicode UTF-8. 前端页面sele.asp <&quo ...
- WebSocket在ASP.NET MVC4中的简单实现 (该文章转自网络,经尝试并未实现,请大神指点。)
WebSocket 规范的目标是在浏览器中实现和服务器端双向通信.双向通信可以拓展浏览器上的应用类型,例如实时的数据推送.游戏.聊天等.有了WebSocket,我们就可以通过持久的浏览器和服务器的连接 ...
- 【网络收集】如何修改vs tfs的登录名和密码 .
连接TFS时,如果本机保存了用户的网络密码,不会出现用户名和密码的输入框,若要更换TFS的用户名和密码,需按以下步骤操作:控制面板--->用户账号--->管理网络密码,此时会列出所有保存了 ...
- RAC监听与tns
监听: 个人理解:本来想通过scan ip来配置tns总数报12545,后来通过vip来配置tns 11g rac的监听在安装时创建,由grid用户管理监听,listener.ora文件在$ORACL ...