孙鑫 第十五/十六课之四 线程同步CriticalSection

说明

在使用多线程时,一般很少有多个线程完全独立的工作。往往是多个线程同时操作一个全局变量来获取程序的运行结果。多个线程同时访问同一个全局变量,如果都是读取操作,则不会出现问题。如果是写操作,则会发生错误。这时候,我们可以通过临界区,为全局变量设置一个保护,保证同时只有一个线程可以访问此变量,其他变量进入等待状态。
      临界区(Critical Section)是一段独占对某些共享资源访问的代码,在任意时刻只允许一个线程对共享资源进行访问。如果有多个线程试图同时访问临界区,那么在有一个线程进入后其他所有试图访问此临界区的线程将被挂起,并一直持续到进入临界区的线程离开。临界区在被释放后,其他线程可以继续抢占,并以此达到用原子方式操作共享资源的目的。

临界区,类似互斥对象Mutex,用起来比较简单,速度快,是比较推荐的一种。

一般步骤:

初始化一个临界区(新建一个电话亭,只能容纳一个人)

等待进入临界区(等待进入电话亭,进入后上锁别人继续等待,如果多次上锁则要多次开锁)

离开临界区(离开电话亭要开锁,以便让其他人进入,有几道锁开几道锁,如果不开锁则别人不能进入)

删除临界区(城管把电话亭拆了)

1 初始化

VOID InitializeCriticalSection(

LPCRITICAL_SECTION   lpCriticalSection  //[out]  CRITICAL_SECTION结构体指针,实际是struct  _RTL_CRITICAL_SECTION类型。

);

初始化一个临界区,相当于新建一个电话亭。

eg.

CRITICAL_SECTION  criticalSection;

InitializeCriticalSection(&criticalSection);

2 进入临界区

VOID  EnterCriticalSection(

LPCRITICAL_SECTION   lpCriticalSection  // [in / out]

);

eg.

EnterCriticalSection(&criticalSection);  //进入临界区,加锁,如果多次加锁则要有多次开锁

3 离开临界区

VOID  LeaveCriticalSection(

LPCRITICAL_SECTION   lpCriticalSection  // [in / out]

);

eg.

LeaveCriticalSection(&criticalSection); //离开临界区,开锁,有几道锁开几道锁

4 删除临界区

VOID  DeleteCriticalSection(

LPCRITICAL_SECTION   lpCriticalSection  // [in / out]

);

删除临界区,前提是临界区必须已经用InitializeCriticalSection函数创建

eg.

DeleteCriticalSection(&criticalSection);

5 实例

两个子线程分别给两个编辑框赋值,用临界区保证他们不同时更新

/////////////////////////////////////74CriticalSectionDlg.h  类声明///////////////////////////////

public:

static UINT MyThread1(LPVOID lpParam);

static UINT MyThread2(LPVOID lpParam);

private:

static CRITICAL_SECTION m_criticalSection;

/////////////////////////////////////74CriticalSectionDlg.cpp  类定义/////////////////////////////

//初始化静态成员变量,该变量为结构体,静态成员变量作为结构体的初始化采用类似形式!

CRITICAL_SECTION CMy74CriticalSectionDlg::m_criticalSection = {0};

//对话框初始化

BOOL CMy74CriticalSectionDlg::OnInitDialog()

{

//codes

InitializeCriticalSection(&m_criticalSection);  //初始化临界区

CWinThread* pThread1 = AfxBeginThread(MyThread1, (LPVOID)&m_ctrlEdit1);  //开启两个线程

CWinThread* pThread2 = AfxBeginThread(MyThread2, (LPVOID)&m_ctrlEdit2);

//codes

}

//子线程1

UINT CMy74CriticalSectionDlg::MyThread1(LPVOID lpParam)

{

CString str;

int a = 0;

CEdit* pEdit = (CEdit*)lpParam;

while (true)

{

EnterCriticalSection(&m_criticalSection); //等待进入临界区,进入后加锁使其他线程不能进入

str.Format("%d", ++a);

str += "  a";

pEdit->SetWindowText(str);

Sleep(100);

if (a >= 1000)

{

LeaveCriticalSection(&m_criticalSection);  //当a>=1000时线程1退出,如果不加此句则线程2永远不能进入临界区

break;

}

LeaveCriticalSection(&m_criticalSection);  //离开 开锁

}

return 0;

}

//子线程2

UINT CMy74CriticalSectionDlg::MyThread2(LPVOID lpParam)

{

CString str;

int b = 0;

CEdit* pEdit = (CEdit*)lpParam;

while (true)

{

EnterCriticalSection(&m_criticalSection);//等待进入临界区,进入后加锁

str.Format("%d", ++b);

str += "  b";

pEdit->SetWindowText(str);

Sleep(100);

LeaveCriticalSection(&m_criticalSection); //离开 开锁

}

return 0;

}

NOTE:如果子线程1或2中调用了多次EnterCriticalSection,在线程退出或一次循环结束时也要调用多次LeaveCriticalSection。

线程同步CriticalSection的更多相关文章

  1. Delphi多线程编程--线程同步的方法(事件、互斥、信号、计时器)简介

    更详细的可以参考:http://www.cnblogs.com/xumenger/p/4450659.html 或者参考之后的博客 四个系统内核对象(事件.互斥.信号.计时器)都是线程同步的手段,从这 ...

  2. Delphi 线程同步技术(转)

    上次跟大家分享了线程的标准代码,其实在线程的使用中最重要的是线程的同步问题,如果你在使用线程后,发现你的界面经常被卡死,或者无法显示出来,显示混乱,你的使用的变量值老是不按预想的变化,结果往往出乎意料 ...

  3. Windows API学习---用户方式中的线程同步

    前言 当所有的线程在互相之间不需要进行通信的情况下就能够顺利地运行时, Micrsoft Windows的运行性能最好.但是,线程很少能够在所有的时间都独立地进行操作.通常情况下,要生成一些线程来处理 ...

  4. windows线程同步的总结

    一 线程 1)如果你正在编写C/C++代码,决不应该调用CreateThread.相反,应该使用VisualC++运行期库函数_beginthreadex,退出也应该使用_endthreadex.如果 ...

  5. windows lua 多线程 线程同步

    今天在改一个程序,改成部分逻辑用lua写,这个程序是多线程的.将程序中部分逻辑改成lua之后,各种非法访问内存错误,各种奇奇怪怪的问题,不分时间,不分地点的出现崩溃.从调用堆栈来看,基本都是使用lua ...

  6. java线程 同步临界区:thinking in java4 21.3.5

    java线程 同步临界区:thinking in java4 21.3.5 thinking in java 4免费下载:http://download.csdn.net/detail/liangru ...

  7. MFC线程(二):线程同步临界区CRITICAL SECTION

    当多个线程同时使用相同的资源时,由于是并发执行,不能保证先后顺序.所以假如时一个公共变量被几个线程同时使用会造成该变量值的混乱. 下面来举个简单例子. 假如有一个字符数组变量 char g_charA ...

  8. Java多线程 | 02 | 线程同步机制

    同步机制简介 ​ 线程同步机制是一套用于协调线程之间的数据访问的机制.该机制可以保障线程安全.Java平台提供的线程同步机制包括: 锁,volatile关键字,final关键字,static关键字,以 ...

  9. [ 高并发]Java高并发编程系列第二篇--线程同步

    高并发,听起来高大上的一个词汇,在身处于互联网潮的社会大趋势下,高并发赋予了更多的传奇色彩.首先,我们可以看到很多招聘中,会提到有高并发项目者优先.高并发,意味着,你的前雇主,有很大的业务层面的需求, ...

随机推荐

  1. [Leetcode] candy 糖果

    There are N children standing in a line. Each child is assigned a rating value. You are giving candi ...

  2. 自定义toolbar教程

    1.写toolbar的布局文件 ,toolbar.xml <?xml version="1.0" encoding="utf-8"?> <Re ...

  3. dbcp基本配置和重连配置

    转载自:http://agapple.iteye.com/blog/772507 最近在看一些dbcp的相关内容,顺便做一下记录,免得自己给忘记了. 1. 引入dbcp (选择1.4) Java代码  ...

  4. Struts2 利用拦截器 interceptor 控制登陆和访问权限

    最近学习了Struts2的登录和权限控制用到的是拦截器,需要在struts.xml中配置,每个action都默认的继承defaultStack,如果你用了别的拦截器,还需要手动引入defaultSta ...

  5. C语言编译各过程

    1.预处理 此阶段主要完成#符号后面的各项内容到源文件的替换,往往一些莫名其妙的错误都是出现在头文件中的,要在工程中注意积累一些错误知识. (1).#ifdef等内容,完成条件编译内容的替换 (2). ...

  6. Flume的安装,配置及使用

    1,上传jar包 2,解压 3,改名 4,更改配置文件 将template文件重镜像 root@Ubuntu-1:/usr/local/apache-flume/conf# cat flume-env ...

  7. [BZOJ1441&BZOJ2257&BZOJ2299]裴蜀定理

    裴蜀定理 对于整系数方程ax+by=m,设d =(a,b) 方程有整数解当且仅当d|m 这个定理实际上在之前学习拓展欧几里得解不定方程的时候就已经运用到 拓展到多元的方程一样适用 BZOJ1441 给 ...

  8. 我在一个前端项目中用js整理的一些通用方法,其中使用到的思想,主要就是约定了。

    把名称和后台来的json数据约定起来,可以达到的效果就是可以将东西统一化,减少差异,提升模块等的通用性,此后就可以实现具体不同模块内容可以自动或拷贝赋值的方式 2016.7.18 refactor s ...

  9. bzoj 2039 最小割模型

    比较明显的网络流最小割模型,对于这种模型我们需要先求获利的和,然后减去代价即可. 我们对于第i个人来说, 如果选他,会耗费A[I]的代价,那么(source,i,a[i])代表选他之后的代价,如果不选 ...

  10. JS形参与实参问题

    JavaScript的参数传递也都是采用值传递的方式进行传值. (1)     通过实参调用函数的时候,传入函数里的是实参的副本而不是实参,因此在函数里面修改参数值并不会对实参造成影响. 例如:将全局 ...