Linux多线程开发(一):用C++封装线程的互斥操作
2013-10-18 22:06
309 查看
学过操作系统的人,估计都知道互斥量是个何方神圣,我这里也就不再狗尾续貂再做解释了
好,先看Linux下关于互斥量的一些API(所谓封装,说白了也就是封装这些API,让这些API更简单好用罢了)
一、Linux下互斥量的使用
1、定义一个互斥量
pthread_mutex_t myMutex;
2、初始化互斥量
pthread_mutex_init( &myMutex, 0); //第2个参数是设置互斥量的属性,如果要使用默认值就设置成0
返回值:成功返回0 ,错误返回错误号
3、使用互斥量
pthread_mutex_lock(&myMutex); //阻塞的方式加锁
pthread_mutex_trylock(&myMutex); //非阻塞的方式加缩
pthread_mutex_unlock(&myMutex); //解锁
返回值:成功返回0,错误返回错误编号
4、销毁互斥量
pthread_mutex_destroy(&myMutex);
二、封装互斥量的方案一
使用方法是,
方案一的问题:
其实正常情况下,方案一是可以满足我们的需要的,但是当程序出错的时候,方案一就不能再胜任工作了,为什么???
考虑这样一种情况,
好了,分析上面的代码,在标志1处,我们给互斥量加锁,然后在标志2处,程序产生了一个异常,as we all know,在try 中产生异常后,程序会在异常代码处终止执行,然后直接跳转到catch块中进行错误处理。
问题来了,当标志2处产生异常后,标志3处代码就不能执行,换句话说,我们不能再进行解锁操作了..
可能有人说,“这好说,我们在catch块中直接再加上一行解锁代码,不就得了吗”,
恩,确实,但是如果我再告诉你,我们在互斥量加锁前(即标志//1之前)或在解锁后(//3 之后)出现了错误,你的解决方法就显得有点太不专业了
好废话半天,拒绝再卖关子,看看土豪们都是怎么封装互斥量吧
线程同步封装方案二:
新版本的互斥量封装是两个类的组合 即 : CMutex(提供互斥量的基本操作) + CEnterCriticalSection(提供互斥量的简单、安全操作)
这个版本的秒处就在于,我们在CEnterCriticalSection的析构函数中调用了互斥量的解锁函数,说起来可能比较晦涩,先看看新版的封装怎么处理
方案一中遇到的问题
或者在其他环境我们可以使用 { } 来确定加锁区域.eg:
分析:
方案二的优点是
1、不许要人为的调用解锁函数unlock
2、操作简单,只需要在加锁区域的开头创造一个局部对象,然后使用{ } 规定该局部变量的生存周期,也就规定了加锁区域的范围
好了,各位小伙伴,千里之行始于足下,赶快动手实验去吧!!!
好,先看Linux下关于互斥量的一些API(所谓封装,说白了也就是封装这些API,让这些API更简单好用罢了)
一、Linux下互斥量的使用
1、定义一个互斥量
pthread_mutex_t myMutex;
2、初始化互斥量
pthread_mutex_init( &myMutex, 0); //第2个参数是设置互斥量的属性,如果要使用默认值就设置成0
返回值:成功返回0 ,错误返回错误号
3、使用互斥量
pthread_mutex_lock(&myMutex); //阻塞的方式加锁
pthread_mutex_trylock(&myMutex); //非阻塞的方式加缩
pthread_mutex_unlock(&myMutex); //解锁
返回值:成功返回0,错误返回错误编号
4、销毁互斥量
pthread_mutex_destroy(&myMutex);
二、封装互斥量的方案一
class CMutex { private: pthread_mutex_t m_Mutex; public: CMutex() { int r = pthread_mutex_init(&m_Mutex,0); if(r != 0) { //错误处理 } } ~CMutex() { int r = pthread_mutex_destroy(&m_Mutex); if(r != 0) { //参数检查 } } CStatus Lock() { int r = pthread_mutex_lock(&m_Mutex); ... } CStatus Unlock() { int r = pthread_mutex_unlock(&m_Mutex); ... } };
使用方法是,
//为了方便操作,先把共享资源和互斥量绑在一个结构体中 struct Data { int sharedSource; CMutex mutex; }; int main() { ... struct Data data; data.mutex.Lock(); data.sharedSource++; data.mutex.Unlock(); ... }
方案一的问题:
其实正常情况下,方案一是可以满足我们的需要的,但是当程序出错的时候,方案一就不能再胜任工作了,为什么???
考虑这样一种情况,
void test() { throw 1; } //测试函数专门用来模拟程序出现异常 void func() { try { struct Data data; data.mutex.Lock(); //1 test(); //2 data.mutex.Unlock();//3 } catch(int) { .... } }
好了,分析上面的代码,在标志1处,我们给互斥量加锁,然后在标志2处,程序产生了一个异常,as we all know,在try 中产生异常后,程序会在异常代码处终止执行,然后直接跳转到catch块中进行错误处理。
问题来了,当标志2处产生异常后,标志3处代码就不能执行,换句话说,我们不能再进行解锁操作了..
可能有人说,“这好说,我们在catch块中直接再加上一行解锁代码,不就得了吗”,
恩,确实,但是如果我再告诉你,我们在互斥量加锁前(即标志//1之前)或在解锁后(//3 之后)出现了错误,你的解决方法就显得有点太不专业了
好废话半天,拒绝再卖关子,看看土豪们都是怎么封装互斥量吧
线程同步封装方案二:
class CEnterCriticalSection { private: CMutex * m_pMutex; public: CEnterCriticalSection(CMutex * pMutex) { ....//参数检查 m_pMutex = pMutex; CStatus s = m_pMutex->Lock(); ...//返回值s 检查 } ~CEnterCriticalSection() { CStatus s = m_pMutex->Unlock(); ...//返回值s检查 } };
新版本的互斥量封装是两个类的组合 即 : CMutex(提供互斥量的基本操作) + CEnterCriticalSection(提供互斥量的简单、安全操作)
这个版本的秒处就在于,我们在CEnterCriticalSection的析构函数中调用了互斥量的解锁函数,说起来可能比较晦涩,先看看新版的封装怎么处理
方案一中遇到的问题
void func() { try { struct Data data; CEnterCriticalSection ecs(&(data.mutex)); data->sharedSource++; test() } catch(..) { } }
或者在其他环境我们可以使用 { } 来确定加锁区域.eg:
void otherFunc() { ... //使用{}来确定加锁区域 { CEnterCriticalSection ecs(&(data.mutex)); .... } //局部变量ecs 的生命周期在这里“}”结束,然后ecs调用自己的析够函数,并在析构函数中解锁, ... }
分析:
方案二的优点是
1、不许要人为的调用解锁函数unlock
2、操作简单,只需要在加锁区域的开头创造一个局部对象,然后使用{ } 规定该局部变量的生存周期,也就规定了加锁区域的范围
好了,各位小伙伴,千里之行始于足下,赶快动手实验去吧!!!
相关文章推荐
- Linux多线程开发(二):使用C++封装线程同步操作
- C++线程封装JAVA线程操作 整体架构类图
- c++多个线程操作与互斥
- Linux多线程开发(三):使用C++封装线程消息通信
- C++线程封装JAVA线程操作
- 【VS开发】cmd dos 批处理重命名文件<不一定非得吭哧吭哧的写C++来操作>
- 一个例子展开,介绍Linux下面线程的操作、多线程的同步和互斥。
- 对System V命名信号量的封装类,用于进程/线程间互斥
- 嵌入式开发之C++基础学习笔记4--面向对象封装继承多态
- 【菜鸟玩Linux开发】在C++里操作MySQL
- 100个windows平台C++开发错误之二VS操作
- 100个windows平台C++开发错误之六数据库操作
- C++封装POSIX 线程库(三)线程的封装
- (六)线程--分别用lock以及Interlocked和Monitor类实现线程的临界区操作(互斥)(示例下载)
- (六)线程--分别用lock以及Interlocked和Monitor类实现线程的临界区操作(互斥)(示例下载)
- 用c++封装一个Hash Table,并与STL map 进行操作性能上的比较
- 【C/C++开发】TinyXml操作(含源码下载)
- C++ 封装 hredis-win32 实现底层操作解耦,并实现自动重连
- Android官方开发文档Training系列课程中文版:线程执行操作之线程间通讯
- SDL的关于线程中互斥锁的条件变量的封装