1、临界区(CCriticalSection)
2、事件(CEvent)
3、互斥量(CMutex)
4、信号量(CSemaphore)
一、使用临界区——CCriticalSection类
当多个线程访问一个独占性共享资源时,可以使用“临界区”对象。
CCriticalSection类的用法步骤如下:
1、定义CCriticalSection类的一个全局对象(以使各个线程均能访问),
如CCriticalSection critical_section;
2、在访问需要保护的资源或代码之前,调用CCriticalSection类的成员Lock()获得临界区对象: critical_section.Lock();
如果此时没有其它线程占有临界区对象,则调用Lock()的线程获得临界区;
否则,线程将被挂起,并放入到一个系统队列中等待,直到当前拥有临界区的线程释放了临界区时为止。
3、访问临界区完毕后,使用CCriticalSection的成员函数Unlock()来释放临界区:
critical_section.Unlock();
说明它的意义我用一个假设来说明:
有两个线程A、B,它们都声明了临界区对象,以访问被保护起来的资源或代码段。
1、在某一时刻,A 拥有了临界区对象,可以访问被保护起来的资源或代码段;
2、此时 B 若想进入临界区,执行critical_section.Lock();,则它被挂起等待,直A 放弃临界区,即执行完critical_section. Unlock();时为止;
这样就保证了不会在同一时刻出现多个线程访问共享资源。
二、使用事件——CEvent类
事件是一个允许一个线程在某种情况发生时,唤醒另外一个线程的同步对象。
每一个CEvent 对象可以有两种状态:有信号状态和无信号状态。
在MFC中,CEvent 类对象有两种类型:人工事件和自动事件。
CEvent 类的各成员函数的原型和参数说明如下:
1、CEvent(BOOL bInitiallyOwn=FALSE, //指定事件对象初始化状态,TRUE为有信号,FALSE为无信号
BOOL bManualReset=FALSE, //TRUE为人工事件,FALSE为自动事件
LPCTSTR lpszName=NULL,
LPSECURITY_ATTRIBUTES lpsaAttribute=NULL);
2、BOOL CEvent::SetEvent(); //将 CEvent 类对象的状态设置为有信号状态。
1)若事件是人工事件, CEvent 类对象保持为有信号状态,直到调用成员函数ResetEvent()将其重新设为无信号状态时为止。
2)若为自动事件,则在SetEvent()将事件设置为有信号状态后,CEvent 类对象由系统自动重置为无信号状态。
如果该函数执行成功,则返回非零值,否则返回零。
3、BOOL CEvent::ResetEvent(); //将事件设置为无信号状态,并保持直至SetEvent()被调用时为止。
自动事件不需要调用该函数。
如果该函数执行成功,返回非零值,否则返回零。
我们一般通过调用WaitForSingleObject函数来监视事件状态。
例如:
在某些网络应用程序中,线程 A 负责监听通讯端口,线程 B 负责更新用户数据。通过使用CEvent 类,线程A可以通知线程B何时更新用户数据。
三、使用互斥量——CMutex类
互斥对象与临界区对象很像。不同在于:
互斥对象可以在进程间使用,而临界区对象只能在同一进程的各线程间使用。
当然,互斥对象也可以用于同一进程的各个线程间,但如果在这种情况下,使用临界区会更节省系统资源,更有效率。
四、使用信号量——CSemaphor类
当需要一个计数器来限制可以使用某个线程的数目时,可以使用“信号量”对象。
CSemaphore 类的构造函数原型及参数说明如下:
CSemaphore (
LONG lInitialCount=1, //初始计数值,即可访问线程数目的初始值
LONG lMaxCount=1, //信号量对象计数值的最大值,决定了同一时刻可访问由信号量保护的资源的线程最大数目
LPCTSTR pstrName=NULL,
LPSECURITY_ATTRIBUTES lpsaAttributes=NULL);
例子:
假设有无数线程,有一个共享资源,它的最大访问量是N,也就是同一时刻可以访问线程数目lMaxCount是N。
每增加一个线程对共享资源的访问,N 减1,只要 N 是大于0的,就可以发出信号量信号;
如果 N=0了,说明当前占用资源的线程数已经达到了所允许的最大数目,不能再允许其它线程的进入,此时的信号量信号将无法发出,访问尝试都被放入到一个队列中等待,直到超时或 N 不为零时为止。
线程在处理完共享资源后,应在离开的同时通过ReleaseSemaphore()函数将当前可用资源数加1。