转:CCriticalSection

类CCriticalSection的对象表示一个“临界区”,它是一个用于同步的对象,同一时刻只允许一个线程存取资源或代码区。临界区在控制一次只能有一个线程修改数据或其它的控制资源时非常有用。例如在链表中增加一个节点就中允许一次一个线程进行。通过使用CCriticalSection对象来控制链表,就可以达到这个目的。

在运行性能比较重要而且资源不会跨进程使用时,建议采用临界区代替信号灯。有关在MFC中使用信号灯的详细信息,请参阅CMutex。使用CCriticalSection对象之前,需要构造它。在构造函数返回后,就可以使用临界区了。在使用完之后要调用UnLock函数。  

存取由CCriticalSection控制的资源时,要在资源的存取函数中定义一个CSingleLock型的变量。然后调用加锁对象的Lock成员函数(如CSingleLock::Lock)。此时,调用的线程要么获得对资源的存取权,要么等待他人释放资源等待加锁,或者等待他人释放资源,但又因为超时而加锁失败。这样就保证了一次只有一个线程在存取临界资源。释放资源只需调用成员函数UnLock(例如CSingleLock:Unlock),或让锁对象在作用范围之外。  

此外,可以单独地建立一个CCriticalSection对象,并在存取临界资源之前显式地存取它。这种方式有助于保持代码的清晰,但是更容易出错,因为程序员要记住在存取临界资源前加锁,存取之后开锁。  #include <afxmt.h>

使隶属于同一进程的各线程协调一致地工作称为线程的同步。MFC提供了多种同步对象,最常用的四种:

  • 临界区(CCriticalSection)
  • 事件(CEvent)
  • 互斥量(CMutex)
  • 信号量(CSemaphore)

本人目前只学习了临界区(CCriticalSection) 的使用,简单介绍如下:

当多个线程访问一个独占性共享资源时,可以使用“临界区”对象。任一时刻只有一个线程可以拥有临界区对象,拥有临界区的线程可以访问被保护起来的资源或代码段,其他希望进入临界区的线程将被挂起等待,直到拥有临界区的线程放弃临界区时为止,这样就保证了不会在同一时刻出现多个线程访问共享资源。

CCriticalSection类的用法非常简单,步骤如下:
 

  1. 定义CCriticalSection类的一个全局对象(以使各个线程均能访问),如CCriticalSection critical_section;
  2. 在访问需要保护的资源或代码之前,调用CCriticalSection类的成员Lock()获得临界区对象:
    critical_section.Lock();
    

    在线程中调用该函数来使线程获得它所请求的临界区。如果此时没有其它线程占有临界区对象,则调用Lock()的线程获得临界区;否则,线程将被挂起,并放入到一个系统队列中等待,直到当前拥有临界区的线程释放了临界区时为止。

  3. 访问临界区完毕后,使用CCriticalSection的成员函数Unlock()来释放临界区:
    critical_section.Unlock();
    

    再通俗一点讲,就是线程A执行到critical_section.Lock();语句时,如果其它线程(B)正在执行critical_section.Lock();语句后且critical_section. Unlock();语句前的语句时,线程A就会等待,直到线程B执行完critical_section. Unlock();语句,线程A才会继续执行。

下面再通过一个实例进行演示说明。

例程:  MultiThread8

  1. 建立一个基于对话框的工程MultiThread8,在对话框IDD_MULTITHREAD8_DIALOG中加入两个按钮和两个编辑框控件,两个按钮的ID分别为IDC_WRITEW和IDC_WRITED,标题分别为“写‘W’”和“写‘D’”;两个编辑框的ID分别为IDC_W和IDC_D,属性都选中Read-only;
  2. 在MultiThread8Dlg.h文件中声明两个线程函数:
    UINT WriteW(LPVOID pParam);
    UINT WriteD(LPVOID pParam);
    
  3. 使用ClassWizard分别给IDC_W和IDC_D添加CEdit类变量m_ctrlW和m_ctrlD;
  4. 在MultiThread8Dlg.cpp文件中添加如下内容:

    为了文件中能够正确使用同步类,在文件开头添加:

    #include "afxmt.h"
    

    定义临界区和一个字符数组,为了能够在不同线程间使用,定义为全局变量:

    CCriticalSection critical_section;
    char g_Array[10];
    

    添加线程函数:

    UINT WriteW(LPVOID pParam)
    {
    	CEdit *pEdit=(CEdit*)pParam;
    	pEdit->SetWindowText("");
    	critical_section.Lock();
    	//锁定临界区,其它线程遇到critical_section.Lock();语句时要等待
    	//直至执行critical_section.Unlock();语句
    	for(int i=0;i<10;i++)
    	{
    		g_Array[i]=‘‘W‘‘;
    	    pEdit->SetWindowText(g_Array);
    		Sleep(1000);
    	}
    	critical_section.Unlock();
    	return 0;
    
    }
    
    UINT WriteD(LPVOID pParam)
    {
    	CEdit *pEdit=(CEdit*)pParam;
    	pEdit->SetWindowText("");
    	critical_section.Lock();
    	//锁定临界区,其它线程遇到critical_section.Lock();语句时要等待
    	//直至执行critical_section.Unlock();语句
    	for(int i=0;i<10;i++)
    	{
    		g_Array[i]=‘‘D‘‘;
    	    pEdit->SetWindowText(g_Array);
    		Sleep(1000);
    	}
    	critical_section.Unlock();
    	return 0;
    
    }
  5. 分别双击按钮IDC_WRITEW和IDC_WRITED,添加其响应函数:
    void CMultiThread8Dlg::OnWritew()
    {
    	CWinThread *pWriteW=AfxBeginThread(WriteW,
    		&m_ctrlW,
    		THREAD_PRIORITY_NORMAL,
    		0,
    		CREATE_SUSPENDED);
    	pWriteW->ResumeThread();
    }
    
    void CMultiThread8Dlg::OnWrited()
    {
    	CWinThread *pWriteD=AfxBeginThread(WriteD,
    		&m_ctrlD,
    		THREAD_PRIORITY_NORMAL,
    		0,
    		CREATE_SUSPENDED);
    	pWriteD->ResumeThread();
    
    }

    由于代码较简单,不再详述。编译、运行该例程,您可以连续点击两个按钮,观察体会临界类的作用。

时间: 2024-10-15 05:48:19

转:CCriticalSection的相关文章

临界段CCriticalSection的使用

类CCriticalSection的对象表示一个“临界区”,它是一个用于同步的对象,同一时刻仅仅同意一个线程存取资源或代码区.临界区在控制一次仅仅有一个线程改动数据或其他的控制资源时很实用.比如,在链表中添加?一个结点就仅仅同意一次一个线程进行.通过使用CCriticalSection对象来控制链表,就能够达到这个目的.它就像是一把钥匙,哪个线程获得了它就获得了执行线程的权力,而把其他线程统统堵塞.CCriticalSection类的构造函数原型例如以下: CCriticalSection()

关键部分CCriticalSection使用

类CCriticalSection的对象表示一个“临界区”,它是一个用于同步的对象,同一时刻仅仅同意一个线程存取资源或代码区.临界区在控制一次仅仅有一个线程改动数据或其他的控制资源时很实用.比如,在链表中添加一个结点就仅仅同意一次一个线程进行.通过使用CCriticalSection对象来控制链表,就能够达到这个目的.它就像是一把钥匙,哪个线程获得了它就获得了执行线程的权力,而把其他线程统统堵塞.CCriticalSection类的构造函数原型例如以下: CCriticalSection() 能

使用CCriticalSection类的注意事项

在类中使用CCriticalSection变量时,必需要将CCriticalSection变量定义为全局变量和静态变量,否则将出现没有定义的错误. 如: // a.h 文件 class A:public CWnd { private: static  CCriticalSection m_cs: ... }: //a.cpp 文件 CCriticalSection   A:m_cs; // 初始化变量 ...

在MFC下面实际演示CCriticalSection 的使用

Q:CCriticalSection是什么? A:CCriticalSection是一种线程同步策略 或者说技术 或者方法  总之呢就是这么个意思.... 参考资料: http://blog.csdn.net/akof1314/article/details/5773076 http://www.cnblogs.com/hlxs/archive/2013/03/31/2991752.html http://baike.baidu.com/view/2471016.htm 第一步:打开VS2010

多线程编程基础知识

多线程编程基础知识 http://www.cnblogs.com/cy163/archive/2006/11/02/547428.html 当前流行的Windows操作系统能同时运行几个程序(独立运行的程序又称之为进程),对于同一个程序,它又可以分成若干个独立的执行流,我们称之为线程,线程提供了多任务处理的能力.用进程和线程的观点来研究软件是当今普遍采用的方法,进程和线程的概念的出现,对提高软件的并行性有着重要的意义.现在的大型应用软件无一不是多线程多任务处理,单线程的软件是不可想象的.因此掌握

“只生一个娃”--设计模式中的单例模式

"只生一个娃"–设计模式中的单例模式(Singleton) 引言 ??被人问到什么是单例模式,突然回答不上来,似乎印象不深了.回去补了一下功课,突然明白了,原来在项目中一直使用的日志模块即采用了单例模式,只是熟视无睹,没有意识到罢了. ??所谓单例模式(Singleton),即指一个类只有一个实例(Instance),并给外界提供访问该实例的一个全局访问点. ??通常我们可以使用全局变量的方式来实现"只生一个娃",但更好的方法就是:让该类自身负责创建和保存它的唯一实

VC多线程临界区(转)

用于理解CriticalSection. 在使用多线程时,一般很少有多个线程完全独立的工作.往往是多个线程同时操作一个全局变量来获取程序的运行结果.多个线程同时访问同一个全局变量,如果都是读取操作,则不会出现问题.如果是写操作,则会发生错误.这时候,我们可以通过临界区,为全局变量设置一个保护,保证同时只有一个线程可以访问此变量,其他变量进入等待状态.       临界区(Critical Section)是一段独占对某些共享资源访问的代码,在任意时刻只允许一个线程对共享资源进行访问.如果有多个线

1.Cocos2d-x-3.2编写3d打飞机,粒子管理器代码

 Cocos2d-x中的一个单例效果: #ifndef __Moon3d__ParticleManager__ #define __Moon3d__ParticleManager__ #include "cocos2d.h" USING_NS_CC; class ParticleManager { public: static ParticleManager* getInstance()//定义获取实例方法,单例设计模式.see notes { if ( m_pInstance =

MFC线程同步初学笔记

一.事件: CEvent类: 声明在头文件afxmt.h中 根据事件对象发信后是否可以自动恢复未发信状态分为自动事件对象和手动事件对象. 构造函数如下: 1 CEvent( 2 3 BOOL bInitiallyOwn = FALSE, //FALSE未发信,禁止系统启动运行正在等待的线程 4 5 BOOL bManualReset = FALSE, //FALSE时自动发信 6 LPCTSTR lpszNAme = NULL, 7 8 LPSECURITY_ATTRIBUTES lpsaAtt