(十一)boost库之多线程间通信
(十一)boost库之多线程间通信
1、互斥锁
在编程中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为" 互斥锁" 的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
#include <iostream>
#include <boost/thread.hpp>
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<boost::shared_mutex> 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<boost::shared_mutex> 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 <queue>
boost::mutex g_ioMutex; //输出控制锁
template<typename T>
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<T> m_val; //队列
int m_nCapacity; //队列最大容量
boost::condition_variable_any m_condPush; //写入条件量
boost::condition_variable_any m_condPop; //读取条件量
boost::mutex m_mu; //互斥锁
};
CMsgQueue<int> 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,故形成了死锁。
(十一)boost库之多线程间通信的更多相关文章
- (十二)boost库之多线程高级特性
(十二)boost库之多线程高级特性 很多时候,线程不仅仅是执行一些耗时操作,可能我们还需要得到线程的返回值,一般的处理方法就是定义一个全局状态变量,不断轮训状态,就如我目前维护的一个项目,全局变量定 ...
- (十)boost库之多线程
(十)boost库之多线程 1.创建线程 使用boost库可以方便的创建一个线程,并提供最多支持9个参数的线程函数,相对于void*来说,方便了很多,创建线程主要提供了一下3种方式: 线程库头文件:# ...
- Java 多线程间通信
JDK 1.5 以后, 将同步和锁封装成了对象, 并将操作锁的隐式方法定义到了该对象中, 将隐式动作变成了显示动作. Lock 接口 Lock 接口, 位于 java.util.concurrent. ...
- Java多线程间通信-解决安全问题、等待唤醒机制
/*1.增加一个知识点一个类怎么在所有的类中,让其它类来共同修改它的数据呢?可以用单例设计模式可以用静态可以在其它类中做一个构造函数,接受同一个对象,这样就可以实现对象 2.状态选择可以用数字0 1 ...
- 多线程间通信之AutoResetEvent和ManualResetEvent的原理分析和开发示例
AutoResetEvent 允许线程通过发信号互相通信. 通常,当线程需要独占访问资源时使用该类. 线程通过调用 AutoResetEvent 上的 WaitOne 来等待信号. 如果 AutoRe ...
- java 多线程间通信(二)
传统的线程通信 Object提供了三个方法wait(), notify(), notifyAll()在线程之间进行通信,以此来解决线程间执行顺序等问题. wait():释放当前线程的同步监视控制器,并 ...
- 多线程间通信之AutoResetEvent和ManualResetEvent的原理分析
AutoResetEvent 允许线程通过发信号互相通信. 通常,当线程需要独占访问资源时使用该类. 线程通过调用 AutoResetEvent 上的 WaitOne 来等待信号. 如果 AutoRe ...
- java 多线程间通信(一)
synchronized同步 package com.test7; public class Run { public class MyObject { private int a; public M ...
- boost库:多线程
1.线程管理 最重要的一个类是boost::thread,是在boost/thread.hpp里定义的,用来创建一个新线程. #include <boost/thread.hpp> #in ...
随机推荐
- [原]bochs+dos6.22汇编环境
1.下载安装bochs 下载MS-DOS http://files.cnblogs.com/allbymyself/DOS6.22.rar 下载Masm5.0 2.bochs配置 1)安装目录下的bx ...
- Mysql基础教程——mysql之一
教程列表:http://www.dxzy163.com/view/index7627.html 41 存储过程 40 全文索引与停止词 39 索引的管 38 索引概念 37 数据库备份与恢复 36 事 ...
- 纯CSS实现三列DIV等高布局
<html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> &l ...
- C语言中的宏定义
目录(?)[-] 简单宏定义 带参数的宏 运算符 运算符 宏的通用属性 宏定义中圆括号 创建较长的宏 较长的宏中的逗号运算符 宏定义中的do-while循环do 空操作的定义 预定义宏 C语言中常用的 ...
- 几道C语言的题目!
注:编译环境 VC2010,系统WIN7 64位,其他编译环境和系统未测试 1-1. 编程,输入n,输出如下例(n=5)所示的图形: ***** ***** ***** ***** ***** # ...
- 【转】如何设置无线路由器的信道以获得最佳WIFI体验?
原文网址:http://jingyan.baidu.com/album/f25ef2546e28e4482c1b8225.html 现在随着移动互联网的发展,移动终端的普及,WIFI越来越必不可少,所 ...
- 【转】在Eclipse中安装和使用TFS插件
文章地址:http://www.cnblogs.com/judastree/archive/2012/09/05/2672640.html 问题: 在Eclipse中安装和使用TFS插件. 解决过程: ...
- CentOS 6.3安装Nginx 搭建文件服务器
转自:http://www.linuxidc.com/Linux/2012-09/70596.htm 1.配置CentOS 6.2 第三方yum源(CentOS默认的标准源里没有nginx软件包): ...
- VC++6.0出现no compile tool is associated with the extension.解决方法
对于刚解除VC++6.0的小白,在编译时候经常出现下图的错误提示: 解释为:不能编译此BmpRot.h文件,没有合适的编译工具可以编译此扩展名的文件. 很明显,当然只有.cpp文件才能编译. .h头文 ...
- mysql sql limit where having order
SQL语句执行顺序及MySQL中limit的用法 . 分类: MySql2013-09-02 09:1315人阅读评论(0)收藏举报 写的顺序:select ... from... where.... ...