boost--线程同步
1、互斥锁(互斥量)
mutex是独占式的互斥锁。timed_mutex增加了超时功能。
成员函数:lock()用于锁定,try_lock()为非阻塞版本的锁定,unlock()用于解锁。timed_lock()只属于timed_mutex,它可以等待一定的时间,等待的时间可以是一个时间段,也可以是指定的时间。
使用方法:使用mutex必须配合try-catch块以保证解锁互斥量,eg:
#include "boost\thread.hpp" int main()
{
boost::mutex mu;
try
{
mu.lock();
cout << "Need to be protected" << endl; //io流是个共享资源,多线程内使用的话需要同步
mu.unlock();
}
catch (...)
{
mu.unlock();
} return ;
}
mutex还提供了一系列的RAII型的互斥锁,用于取消麻烦的try-catch块,它会在构造的时候锁定互斥量,析构时自动解锁,eg:
#include "boost\thread.hpp" int main()
{
boost::mutex mu;
boost::mutex::scoped_lock lock(mu);
cout << "Need to be protected" << endl; //io流是个共享资源,多线程内使用的话需要同步 return ;
}
使用实例:以下定义了一个支持原子前++的计数器atom_increase:
#include "boost\thread.hpp" template<typename T>
class atom_increase
{
public:
atom_increase(T x = ): n(x){} //转换构造函数,实现T类型到atom_increase类型的隐式转换 T operator++() //重载前++运算符
{
boost::mutex::scoped_lock lock(mu);
return ++n;
} operator T() { return n; } //类型转换函数,实现atom_increase类型到T类型的隐式转换 private:
T n;
boost::mutex mu;
}; int main()
{
atom_increase<int> n = ; //隐式转换:int -> atom_increase
++n; //原子前++
int i = + n; //隐式转换:atom_increase ->int return ;
}
2、递归锁
recursive_mutex是递归锁,可以多次锁定,相应的也要多次解锁。recursive_timed_mutex增加了超时功能。递归锁的使用接口跟互斥锁基本相同。
3、读写锁
shared_mutex是读写锁,提供了multiple-reader / single-writer功能。读取锁定时我们使用shared_lock<shared_mutex>对象,写入锁定时我们使用unique_lock<shared_mutex>对象:
boost::shared_mutex rw_mu;
//read thread
{
boost::shared_lock<boost::shared_mutex> sl(rw_mu); //读锁定
//......
}
//write thread
{
boost::unique_lock<boost::shared_mutex> ul(rw_mu); //写锁定
//......
}
4、条件变量
condition_variable_any是条件变量,它用来在一个线程中等待某个事件的发生(满足某个条件),另一个线程会使条件成立。条件变量需要与一个互斥量配合使用。condition_variable_any::wait()用来等待条件满足,wait_for()用来等待条件满足直到超时,wait_until()用来等待条件满足直到指定的时间, condition_variable_any::notify_one() / notify_all()用来在条件满足的时候通知条件变量。
boost中的条件变量的使用方法与posix或windows下条件变量使用方法基本一致:
#include "boost\thread.hpp" boost::condition_variable_any g_cd;
boost::mutex g_mu;
bool g_bConditionFlag = false; void Thread1Proc()
{
boost::mutex::scoped_lock lock(g_mu);
while (!g_bConditionFlag)
{
boost::this_thread::sleep(boost::posix_time::seconds());
g_cd.wait(g_mu);
} printf("thread1 exit\n");
} int main()
{
boost::thread t(Thread1Proc);
t.detach();
boost::this_thread::sleep(boost::posix_time::milliseconds()); g_mu.lock();
g_bConditionFlag = true;
g_cd.notify_one();
g_mu.unlock(); printf("here\n");
getchar(); return ;
}
5、barrier
barrier称为护栏,它可以用来设置线程执行到barrier时必须等待,直到所有线程都达到这个点时才继续执行。
6、C++11中的线程操作
c++11也提供了创建线程和线程同步的方法,c++11里的mutex,与boost里的mutex用法类似:
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::lock std::mutex foo, bar; void task_a()
{
// foo.lock();
// bar.lock();
std::lock(foo, bar);
std::cout << "task a\n"; foo.unlock();
bar.unlock();
} void task_b()
{
// bar.lock();
// foo.lock();
std::lock(bar, foo);
std::cout << "task b\n";
bar.unlock();
foo.unlock();
} int main()
{
std::thread th1(task_a);
std::thread th2(task_b);
// th1.detach();
// th2.detach();
th1.join();
th2.join(); return ;
}
创建线程的时候需要注意三点:
①、如果使用函数对象作为thread的参数的话,直接传入临时对象会出错,可以定义一个对象传入或者使用lambda表达式:
class CTask
{
public:
void operator()()
{
int a = ;
}
}; //std::thread th1(CTask()); //直接传入临时对象会出错
CTask task;
std::thread th1(task);
th1.join();
②、传递给线程函数的参数是先保存在于一个中转站中,当函数执行的时候再传给函数的形参,而这个时候传递的参数指向的值很有可能已经失效,所以,对于线程函数传递的参数应该与形参类型相同,而不是再进行转换。
③、如果线程函数的参数是引用的话传入时还需要结合ref来使用。
void task(int& a, string str)
{ } int iNum = ;
char* pStr = new char[];
strcpy(pStr, "test");
//std::thread th(task, 5, std::ref(iNum), pStr); //不应该直接传入pStr
std::thread th(task, std::ref(iNum), string(pStr)); //应该传入对应类型
delete[] pStr;
th.join();
c++中的lock_guard、unique_lock也是RAII型的互斥锁,类似boost的scoped_lock,使用示例:
std::lock_guard<std::mutex> _lock(m_mutex);
g_num++;
unique_lock在lock_guard的基础上增加了加锁和解锁的接口方法,对比下面的fun1和fun2,二者效果相同,通过代码可以看出二者区别:
std::mutex g_mu; void fun1()
{
{
std::lock_guard<std::mutex> guard(g_mu);
//do something 1
} //do something 2 {
std::lock_guard<std::mutex> guard(g_mu);
// do something 3
}
} void fun2()
{
std::unique_lock<std::mutex> guard(g_mu);
//do something 1
guard.unlock(); //do something 2 guard.lock();
// do something 3
}
unique_lock可以配合条件变量来使用,而lock_guard不能,因为lock_guard没有加锁和解锁的接口方法。另外,unique_lock和lock_guard都不能复制,unique_lock可以移动,lock_guard不能移动。c++11中的条件变量condition_variable与boost的使用类似,其接口方法有wait()、notify_one()等。
boost--线程同步的更多相关文章
- BOOST 线程完全攻略 - 基础篇
http://blog.csdn.net/iamnieo/article/details/2908621 2008-09-10 12:48 9202人阅读 评论(3) 收藏 举报 thread多线程l ...
- BOOST 线程完全攻略
1 创建线程 首先看看boost::thread的构造函数吧,boost::thread有两个构造函数: (1)thread():构造一个表示当前执行线程的线程对象: (2)explicit thre ...
- Boost 线程学习笔记
Bolg转载自:http://www.cnblogs.com/lvdongjie/p/4447193.html 一: 创建线程 #include <iostream> #include & ...
- 从零开始构建一个Reactor模式的网络库(一) 线程同步Mutex和Condition
最近在学习陈硕大神的muduo库,感觉写的很专业,以及有一些比较“高级”的技巧和设计方式,自己写会比较困难. 于是打算自己写一个简化版本的Reactor模式网络库,就取名叫mini吧,同样只基于Lin ...
- 【C/C++】BOOST 线程完全攻略 - 基础篇
C++多线程开发是一个复杂的事情,mfc下提供了CWinThread类,和AfxBeginThread等等函数,但是在使用中会遇到很多麻烦事情,例如线程之间参数传递的问题,我们一般都是把参数new一个 ...
- c++ 跨平台线程同步对象那些事儿——基于 ace
前言 ACE (Adaptive Communication Environment) 是早年间很火的一个 c++ 开源通讯框架,当时 c++ 的库比较少,以至于谈 c++ 网络通讯就绕不开 ACE, ...
- [ 高并发]Java高并发编程系列第二篇--线程同步
高并发,听起来高大上的一个词汇,在身处于互联网潮的社会大趋势下,高并发赋予了更多的传奇色彩.首先,我们可以看到很多招聘中,会提到有高并发项目者优先.高并发,意味着,你的前雇主,有很大的业务层面的需求, ...
- C#多线程之线程同步篇3
在上一篇C#多线程之线程同步篇2中,我们主要学习了AutoResetEvent构造.ManualResetEventSlim构造和CountdownEvent构造,在这一篇中,我们将学习Barrier ...
- C#多线程之线程同步篇2
在上一篇C#多线程之线程同步篇1中,我们主要学习了执行基本的原子操作.使用Mutex构造以及SemaphoreSlim构造,在这一篇中我们主要学习如何使用AutoResetEvent构造.Manual ...
- C#多线程之线程同步篇1
在多线程(线程同步)中,我们将学习多线程中操作共享资源的技术,学习到的知识点如下所示: 执行基本的原子操作 使用Mutex构造 使用SemaphoreSlim构造 使用AutoResetEvent构造 ...
随机推荐
- 微信小程序开发——使用回调函数出现异常:TypeError: Cannot read property 'setData' of undefined
关键技术点: 作用域问题——回调函数中的作用域已经脱离了调用函数了,因此需要在回调函数外边把this赋给一个新的变量才可以了. 业务需求: 微信小程序开发,业务逻辑需要,需要把获取手机号码的业务逻辑作 ...
- mac上将代码上传到github
前言 有时我们会写一些小程序来学习新的知识,但是完事之后过一段时间可能会忘记,最好的办法就是找到原来的代码看一看.现在可以将代码免费托管到一些网站上,其中最著名的非github莫属了, 今天就把这个过 ...
- 【python中单链表的实现】——包括初始化、创建、逆序、遍历等
# coding=utf-8 class mynode(object): def __init__(self, data, nextnode = None): self.data = data sel ...
- Javascript 四种输出方式
JavaScript 输出 javascript 没有任何打印或输出的函数 可以通过不同的方式输出数据 使用window.alert() 弹出警告框 使用document.write()方法将内容写到 ...
- redis 哨兵(sentinel)
redis哨兵 哨兵自动故障转移 自动通知应用最新master信息 无需担心,master挂了,程序不需要修改IP啥的,由哨兵自动完成 修改sentinel.conf protected-mode n ...
- mysql 查两个表之间的数据差集
需要查两个表之间的差集 首先,想到的是主键直接not in select mailbox_id from co_user where mailbox_id not in (select mailbox ...
- Python之socket编程进阶版
1.socket之简单的ssh功能 2.socket之简单的ftp服务器 3.socketserver的用法 4.socketserver的多并发的实现 1.socket实现ssh服务 1.1我们现在 ...
- Trapping Rain Water LT42
The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of ...
- 【算法】BFS+哈希解决八数码问题
15拼图已经有超过100年; 即使你不叫这个名字知道的话,你已经看到了.它被构造成具有15滑动砖,每一个从1到15上,并且所有包装成4乘4帧与一个瓦块丢失.让我们把丢失的瓷砖“X”; 拼图的目的是安排 ...
- svn 修改原来包名的方法和会报的错误
SVN E200009 which is not part of the commit; both sides of the move must be committed together 在svn上 ...