转:CCriticalSection「建议收藏」

转:CCriticalSection「建议收藏」类CCriticalSection的对象表示一个“临界区”,它是一个用于同步的对象,同一时刻只允许一个线程存取资源或代码区。临界区在控制一次只能有一个线程修改数据或其它的控制资源时非常有用。例如在链表中增加一个节点就中允许一次一个线程进行。通过使用CCriticalSection对象来控制链表,就可以达到这个目的。在运行性能比较重要而且资源不会跨进程使用时,建议采用临界区代替信号灯。有关在MF…

大家好,又见面了,我是你们的朋友全栈君。

类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();
    	
    }

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

转载于:https://www.cnblogs.com/killer-xc/p/6612482.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/162038.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • jQuery 文档操作 – remove() 方法

    jQuery 文档操作 – remove() 方法

    2021年10月17日
    72
  • G6流程图绘制

    G6流程图绘制为了能在线编辑流程 支持流程节点编辑等功能 支持人员等选择功能 支持流程图数据保存 利用阿里 G6 进行设计开发 整体效果图如下 支持放大缩小 节点移动 添加节点及边等 同时支持节点及边删除操作 流程图数据保存等工作 支持节点编辑 包括人员选择 图形选择 宽高编辑 背景色 边框色等信息编辑 支持边的编辑 边描述等 各种交互功能就不赘述了 页面代码如下 DOCTYPE YPE html head head html

    2025年7月25日
    2
  • Java 删除文件以及文件夹删除不了的问题

    Java 删除文件以及文件夹删除不了的问题问题所在今天在编写一个项目,流程是先创建一个临时文件夹存放生成的文件,再经过压缩导出,待导出成功后删除临时文件夹,但是怎么也删除不了,还以为是写的删除方法有问题,找来找去,试了很多方法也删除不了本来以为是打包的流没关闭,但是发现流都是关闭的,后来发现,是在生成的方法里,直接newFileWriter出来的,没有关闭,在这里提醒一下,关于操作文件或者文件夹一定都会用到流,所以用到的流一…

    2022年6月7日
    33
  • 当前汇总(最新序列号破解)「建议收藏」

    当前汇总(最新序列号破解),https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月20日
    45
  • delphi多线程[通俗易懂]

    delphi多线程[通俗易懂]   Delphi中有一个线程类TThread是用来实现多线程编程的,这个绝大多数Delphi书藉都有说到,但基本上都是对TThread类的几个成员作一简单介绍,再说明一下Execute的实现和Synchronize的用法就完了。然而这并不是多线程编程的全部,我写此文的目的在于对此作一个补充。  线程本质上是进程中一段并发运行的代码。一个进程至少有一个线程,即所谓的主线程。同时还可以有多个子线

    2025年8月22日
    2
  • C++ merge函数

    C++ merge函数C++merge函数首先,merge()函数调用前必须保L1,L2是有序的,然后才能调用merge()函数。所以应该做两处更改:1.在worker类的公有函数中添加以下定义排序准则的函数。booloperator&lt;(constworker&amp;kk) { returnthis-&gt;age&lt;kk.getAge(); }2.在调用…

    2022年6月7日
    146

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号