孙鑫 第十五/十六课之四 线程同步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。

最新文章

  1. c语言问卷调查
  2. Scala可变长度参数
  3. SQL Server ->> EXECUTE AS LOGIN/USER和Revert表达式
  4. 0601 Spring2.0 发布会及产品发展方向
  5. 用javascript实现用户登录验证
  6. H2的MVStore
  7. PHP中使用多线程
  8. Apache-rhel5.8环境下编译安装
  9. 一笔画问题(floyd+oular+dfs)
  10. Java基础:多态(重载和重写)
  11. Java-8ATM
  12. scheme深拷贝和浅拷贝探索
  13. RIDE安装操作
  14. 返回通知的方法 是void
  15. ObservableCollection<T> 类
  16. xhan/qqbot试用
  17. bzoj 3144
  18. 十大开源ERP点评 献给深水区的中小企业和CIO们
  19. 【Handler】Looper 原理 详解 示例 总结
  20. Python 创建元组tuple

热门文章

  1. 【BZOJ 1724】[Usaco2006 Nov]Fence Repair 切割木板 堆+贪心
  2. Different Integers 牛客多校第一场只会签到题
  3. Covered Points Count(思维题)
  4. springboot搭建web项目(转)
  5. nginx对指定目录做代理
  6. wget命令下载FTP整个目录进行文件备份
  7. CSS选择器及CSS3新增选择器
  8. HDU2057
  9. AQS同步组件及ReentrantLock和synchronized的区别
  10. 【BZOJ】1708: [Usaco2007 Oct]Money奶牛的硬币