博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
(十一)boost库之多线程间通信
阅读量:6057 次
发布时间:2019-06-20

本文共 3482 字,大约阅读时间需要 11 分钟。

(十一)boost库之多线程间通信

1、互斥锁

在中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为" 互斥锁" 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。

#include 
#include 
using namespace std;
 
int g_num = 0;
boost::mutex mu;  //定义互斥锁对象
 
int Func(int nCount)
{
for (int i = 0; i < nCount; i++)
{
boost::mutex::scoped_lock lock(mu);  //对共享数据进行操作,需加锁
g_num++;
cout << __FUNCTION__ << ": " << g_num << endl;
}
return g_num;
}
 
int _tmain(int argc, _TCHAR* argv[])
{
boost::thread th1(Func, 100);
boost::thread th2(Func, 200);
th1.join();
th2.join();
return 0;
}

2、读写锁

 
boost::shared_mutex rw_mu;   //定义读写锁
int Write(int nCount)
{
for (int i = 0; i < nCount; i++)
{
boost::unique_lock
lock(rw_mu); //加唯一锁
g_num++;
cout << __FUNCTION__ << ": " << g_num << endl;
}
return g_num;
}
 
void Read(int nCount)
{
for (int i = 0; i < nCount; i++)
{
boost::shared_lock
lock(rw_mu); //加共享锁
cout << __FUNCTION__ << ": " << g_num << endl;
}
}
 
int _tmain(int argc, _TCHAR* argv[])
{
boost::thread th1(Write, 100);
boost::thread th2(Read, 100);
boost::thread th3(Read, 100);
th1.join();
th2.join();
th3.join();
return 0;
}

3、条件量

条件量相对于互斥锁和读写锁来说,并不是那么好理解,简单点说,条件变量就是用于等待某个条件被触发,但为什么要配合锁使用呢,因为我们的等待不能是干等,那样可能会出现死锁。

如线程A负责添加任务到队列,线程B负责处理队列中的任务,队列就是两个线程的共享资源,使用前必须加锁,但如果B线程加锁后,发现队列中没有数据,然后等待,A线程准备添加任务时,发现

锁已经被占用,于是就没法添加任务,就形成了死锁。但如果我等待时,释放锁资源,A线程就能正常添加任务,完成后通知B线程可以处理了,那么整个流程就畅通无阻了,这就是条件量的作用。

 
#include 
boost::mutex g_ioMutex;    //输出控制锁
template
class CMsgQueue
{
public:
CMsgQueue(size_t n):m_nCapacity(n)
{
}
void Push(const T& val)
{
{
boost::mutex::scoped_lock lock(m_mu);              //加锁
while(m_val.size() == m_nCapacity)                 //队列已满
{
{
boost::mutex::scoped_lock lock(g_ioMutex);
cout << "队列已满" << endl;
}
m_condPush.wait(m_mu);                         //等待,将暂时的解锁
}
m_val.push(val);                                   //添加数据到队列
}
m_condPop.notify_one();                                 //通知读线程
}
void Pop(T& val)
{
{
boost::mutex::scoped_lock lock(m_mu);               //加锁
while(m_val.size() == 0)                            //队列为空
{
{
boost::mutex::scoped_lock lock(g_ioMutex);
cout << "队列为空" << endl;
}
m_condPop.wait(m_mu);                           //等待可读,
}
val = m_val.front();                                 //读取数据
m_val.pop();
}
m_condPush.notify_one();                                 //通知写线程
}
 
private:
queue
m_val; //队列
int m_nCapacity;                           //队列最大容量
boost::condition_variable_any m_condPush;  //写入条件量
boost::condition_variable_any m_condPop;   //读取条件量
boost::mutex m_mu;                         //互斥锁
};
 
CMsgQueue
g_numQueue(10);
void FuncA(int nCount)
{
for (int i = 0; i < nCount; i++)
{
{
boost::mutex::scoped_lock lock(g_ioMutex);
cout << __FUNCTION__ << " Put " << i << endl;
}
g_numQueue.Push(i);
 
}
}
 
void FuncB(int nCount)
{
for (int i = 0; i < nCount; i++)
{
int val;
g_numQueue.Pop(val);
boost::mutex::scoped_lock lock(g_ioMutex);
cout << __FUNCTION__ << " Get " << val << endl;
}
}
 
int _tmain(int argc, _TCHAR* argv[])
{
boost::thread th1(FuncA, 50);
boost::thread th2(FuncB, 20);
boost::thread th3(FuncB, 30);
th1.join();
th2.join();
th3.join();
return 0;
}

在多线程程序中,锁的使用需要特别的小心,比如,我们将FuncA稍微改一下:

void FuncA(int nCount)
{
for (int i = 0; i < nCount; i++)
{
boost::mutex::scoped_lock lock(g_ioMutex);
cout << __FUNCTION__ << " Put " << i << endl;
g_numQueue.Push(i);
}
}

如果改成这样,程序将陷入死锁,我们轻轻松松就制造了一个死锁案例。

A线程占用了输入锁,那么B线程的Pop函数将一直在获取输入锁的地方等待,但它已经占用了m_mu锁,A线程也就只能一直在等待m_mu,故形成了死锁。

转载地址:http://mrdrx.baihongyu.com/

你可能感兴趣的文章
十年软件测试经验总结
查看>>
自定义eclipse 部署项目路径
查看>>
第十节 19爆力注册
查看>>
设计模式----观察者模式通俗实例
查看>>
VB.net 字符串 分割 及 重新倒序组装
查看>>
Envoy为什么能战胜Ngnix——线程模型分析篇
查看>>
SIGIR2018高分录用——阿里妈妈公开全新CVR预估模型
查看>>
BAT架构师java面试经验总结
查看>>
2018年杭州GDP预计达1.35万亿 增长目标下调至7%左右
查看>>
冰雪嘉年华开启宁夏冬季旅游狂欢
查看>>
数据产品必备技术知识:数据仓库入门
查看>>
Unity中使用sLua的 超丶简单基础教程
查看>>
【CuteJavaScript】Angular6入门项目(1.构建项目和创建路由)
查看>>
saiku+kettle整合(七)二次开发saiku
查看>>
NDK之旅必须要知道的一些基本知识
查看>>
JavaScript 魔幻代理
查看>>
【翻译】ECMAScript装饰器的简单指南
查看>>
VSCode shortcuts configuration file
查看>>
BCH正在蔓延到更广泛的行业中去
查看>>
再谈函数和一等公民
查看>>