OSMutex/OSCond Class
来源:互联网 发布:手机迅雷提示无网络 编辑:程序博客网 时间:2024/06/11 09:44
在有多个线程并发运行的环境中,能同步不同线程的活动是很重要的,DSS开发了OSMutex和OSCond两个类用以封装不同*作系统对线程同步支持的差异。
我们首先分析OSMutex类,这个类定义了广义互斥量的基本*作,类定义如下:
class OSMutex
{
1 public:
2 OSMutex(); //构造函数
3 ~OSMutex(); //析构函数
4 inline void Lock(); //加锁
5 inline void Unlock(); //解锁
6 inline Bool16 TryLock(); //异步锁,无论是否成功立即返回
7 private:
8 #ifdef __Win32__
9 CRITICAL_SECTION fMutex; //临界区
10 DWORD fHolder; //拥有临界区的线程id
11 UInt32 fHolderCount; //进入临界区线程数
//其他略…
}
在 Windows平台上,OSMutex类是通过临界区(CRITICAL_SECTION)来实现的,第10行定义了临界区变量fMutex。类实例化时 构造函数调用InitializeCriticalSection(&fMutex)初始化临界区变量,对应的在析构函数中调用 DeleteCriticalSection(&fMutex)清除。
Lock()函数用于对互斥量加锁,它调用私有方法RecursiveLock实现:
void OSMutex::RecursiveLock()
{
// 当前线程已经拥有互斥量,只需增加引用计数
1 if (OSThread::GetCurrentThreadID() == fHolder)
2 {
3 fHolderCount++; //增加引用计数
4 return;
5 }
6 #ifdef __Win32__
7 ::EnterCriticalSection(&fMutex); //申请进入临界区
8 #else
9 (void)pthread_mutex_lock(&fMutex);
10 #endif
11 Assert(fHolder == 0);
12 fHolder = OSThread::GetCurrentThreadID(); //更新临界区拥有者标志
13 fHolderCount++;
14 Assert(fHolderCount == 1);
}
第1行检测如果当前线程已经拥有互斥量,就只需将内部计数fHolderCount加1,以便纪录正在使用互斥量的方法数。如果当前线程还没有得到互斥 量,第7行调用EnterCriticalSection()函数申请进入临界区;如果当前已经有其他线程进入临界区,该函数就会阻塞,使得当前线程进入 睡眠状态,直到占用临界区的线程调用LeaveCriticalSection(&fMutex)离开临界区后才可能被唤醒。一旦线程进入临界区 后,它将首先更新临界区持有者标志(第12行),同时将临界区引用计数加1。
注意到另外一个函数TryLock(),该函数也是用于为互斥量加锁,但与Lock()不同的是,TryLock()函数为用户提供了异步调用互斥量的功 能,这是因为它调用::TryEnterCriticalSection(&fMutex)函数申请进入缓冲区:如果临界区没有被任何线程拥有, 该函数将临界区的访问区给予调用的线程,并返回TRUE,否则它将立刻返回FALSE。TryEnterCriticalSection()和 EnterCriticalSection()函数的本质区别在于前者从不挂起线程。
接着分析OSCond类,该类定义了状态变量(Condition Variable)的基本*作,类定义如下:
class OSCond
{
1 public:
2 OSCond(); //构造函数
3 ~OSCond(); //析构函数
4 inline void Signal(); //传信函数
5 inline void Wait(OSMutex* inMutex, SInt32 inTimeoutInMilSecs = 0);//释放锁inMutex,在等待到信号后,再重新给inMutex加锁
//等待传信函数
6 inline void Broadcast(); //广播传信函数
7 private:
8 #ifdef __Win32__
9 HANDLE fCondition; //事件句柄
10 UInt32 fWaitCount; //等待传信用户数
//其他略…
}
虽然同是用于线程同步,但OSCond类与OSMutex大不相同,后者用来控制对关键数据的访问,而前者则通过发信号表示某一*作已经完成。在 Windows平台中,OSCond是通过事件(event)来实现的;构造函数调用CreateEvent()函数初始化事件句柄 fCondition,而析构函数则调用CloseHandle()关闭句柄。
OSCond的使用流程是这样的:线程调用Wait(OSMutex* inMutex, SInt32 inTimeoutInMilSecs = 0)函数等待某个事件的发生,其中inTimeoutInMilSecs是最长等待时间,0代表无限长。Wait()函数内部调用了 WaitForSingleObject (fCondition, theTimeout)函数,该函数告诉系统线程在等待由事件句柄fCondition标识的内核对象变为有信号,参数theTimeout告诉系统线程 最长愿意等待多少毫秒。如果指定的内核对象在规定时间内没有变为有信号,系统就会唤醒该线程,让它继续执行。而函数Signal()正是用来使事件句柄 fCondition有信号的。Signal()函数内部实现很简单,只是简单调用SetEvent函数将事件句柄设置为有信号状态。
使用OSCond的过程中存在一种需求,就是希望通知所有正在等待的用户事件已经完成,而Signal()函数每次只能通知一个用户,因此又开发了另外一个广播传信函数如下:
inline void OSCond::Broadcast()
{ //提示:本函数相当循环调用Signal()函数
1 #ifdef __Win32__
2 UInt32 waitCount = fWaitCount; //等待传信的用户数
3 for (UInt32 x = 0; x < waitCount; x++) //循环为每个用户传信
4 {
5 BOOL theErr = ::SetEvent(fCondition); //设置事件句柄为有信号状态
6 Assert(theErr == TRUE);
7 }
//此处略…
}
Broadcast首先统计所有等待传信的用户数(第2行),然后用一个循环为每个用户传信(第3~7)行。这种编程方法虽然不是很优雅(elegant),但是由于Windows平台上不支持广播传信功能(Linux和Solaris均支持),也只好如此。
- OSMutex/OSCond Class
- dss源码分析1:OSMutex
- class
- class
- class
- class
- class
- class
- Class
- Class
- class
- Class
- Class<?>
- class
- Class
- Class<?>
- Class
- @class
- Linux 中/var/spool/postfix/maildrop目录下堆积大量小文件
- 算法基础之字符串2
- 指令和控制器之间的交互
- nginx 重写规则,过滤某些url
- 曾经使用过的Linux命令
- OSMutex/OSCond Class
- Java RMI
- js常用正则校验
- js数组的操作
- java学习------引用
- objectId生成可读性唯一ID
- 自己动手和php-fpm通讯
- JavaScript 自执行函数简述
- 微信小程序组件及API的思维导图