孙鑫 第十五/十六课之四 线程同步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. COGS 930. [河南省队2012] 找第k小的数 主席树

    主席树裸板子 #include<cstdio> #include<iostream> #include<algorithm> #define MAXN 100005 ...

  2. Dilworth定理证明

    命题:偏序集能划分成的最少的全序集的个数与最大反链的元素个数相等. (离散数学结构第六版课本P245:把一个偏序集划分成具有全序的子集所需要的最少子集个数与元素在偏序下都是不可比的最大集合的基数之间有 ...

  3. Join to domain powershell script

    Join to domain powershell script $username = "domain\admin" $Password = "xxxxxxxx&quo ...

  4. 【转载】How long is “too long” for MySQL Connections to sleep?

    From:http://dba.stackexchange.com/questions/1558/how-long-is-too-long-for-mysql-connections-to-sleep ...

  5. classList详解,让你的js方便地操作DOM类

    在此之前,jQuery的hasClass.addClass.removeClass我们已经再熟悉不过了,然而我们并不会在每一个项目中都会去使用 jQuery或者Zepto,譬如在移动端的网页中,考虑到 ...

  6. windows下mysql 5.7的配置全过程

    这是一套在好多次的安装下总结出来的经验,包括很多种遇到的问题,查过很多资料,特此总结一下. 一.从官网下载MySQL的zip(免安装的) 解压mysql-5.7.11-winx64.zip到自己指定的 ...

  7. JS形参与实参问题

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

  8. 如何使用SDK在Ubuntu设备(包括仿真器和桌面)上运用应用程序

    简介 有三种运行通过SDK创建的应用程序的方式:在桌面上,在联网的Ubuntu设备上,以及在仿真器中.这些方式为互补性方式,因为各有优缺点.您首先将了解如何管理SDK的设备类型,以及哪一个类型用于测试 ...

  9. Linux 邮件服务器 之跟我一步一步来实现一个邮件系统【转】

    转自:http://tchuairen.blog.51cto.com/3848118/1686875/ 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法 ...

  10. python学记笔记 2 异步IO

    在IO编程中,我们知道CPU的速度远远快于磁盘,网络IO,在一个线程中,CPU执行速度的代码非常快,然而遇到IO操作就需要阻塞 需要等待IO操作完成才能继续下一步的动作.这种情况叫做同步IO 在IO操 ...