当多个线程同时使用相同的资源时,由于是并发执行,不能保证先后顺序.所以假如时一个公共变量被几个线程同时使用会造成该变量值的混乱.

下面来举个简单例子.

假如有一个字符数组变量

char g_charArray[4];

CString szResult;

AfxBeginThread(FunOne,NULL);  //FunOne给数组赋值全为S

AfxBeginThread(FunTwo,NULL); //FunTwo也给数组赋值全为B

AfxBeginThread(GetResult,NULL);   //得到数组的值,本来期望的值为最后一次赋的值BBBB.但实际结果是不确定的,可能是SBSB,SSBB或者其它

UINT FunOne(LPVOID pParam){ //给数组赋值

for(int i =0; i < 4; i++){

g_charArray[i] = 'S';

Sleep(10);

}

return 0;

}

UINT FunTwo(LPVOID pParam){//得到数组值

for(int i =0; i < 4; i++){

g_charArray[i] = 'B';

Sleep(10);

}

return 0;

}

UINT GetResult(LPVOID pParam){//给数组赋值

szResult = CString(g_charArray);

return 0;

}

Win32 API中临界区(Critical Section)

为了使公共变量不会被毫无秩序,混乱的更改.我们希望一个线程使用这个变量时其他线程就不能使用,只能等别的线程用完了才用.

于是出现了临界区这说法,相当于把使用到的变量的内存看作一块区域,当某个线程使用时就进入该区域,使用完了离开.当有一个线程进入该区域时其他线程就只能在外面等.临界区的使用如下.

临界区只能用于同一个进程内的线程同步.如果想要多个进程间的线程同步就不能用它了.

CRITICAL_SECTION g_criSection //定义临界区变量

void MainTestFun{

InitializeCriticalSection(&g_criSection);  //使用前必须初始化

char g_charArray[4];

CString szResult;

AfxBeginThread(FunOne,NULL);

AfxBeginThread(FunTwo,NULL);

AfxBeginThread(GetResult,);  //此时得到的值总是BBBB或者SSSS,哪一个线程拥有临界区不确定.只能保证某一个时间只能有一个线程拥有

//DeleteCriticalSection(&g_criSection); 使用完了临界区就要删除掉,但是在这里这样使用可能会出错.因为必须保证在删除时这个临界区没有再被使用了.所以如果一个类中,一般把它放析构函数中去调用.

}

//在线程调用的函数的开始调用EnterCriticalSection结束时调用CriticalSection(&g_criSection);

//在中间有用到的所有资源在被使用时其他线程不能使用(不能读也不能改写).其它两个函数FunOne,GetResult按同样的方法添加这两行代码.这里不再写出来了.

UINT FunOne(LPVOID pParam){

EnterCriticalSection(&g_criSection); //表示进入临界区

for(int i =0; i < 4; i++){

g_charArray[i] = 'S';

Sleep(1);

}

LeaveCriticalSection(&g_criSection); //离开临界区

return 0;

}

MFC中的临界区类

MFC把上面的操作封装成一个类CCriticalSection,使用函数Lock与Unlock表示进入和离开临界区.上锁和解锁的说法是更符合我们的习惯思维的.

#include "afxmt.h" //需要添加该头文件引用

CCriticalSection g_criSection;

void MainTestFun{

char g_charArray[4];

CString szResult;

AfxBeginThread(FunOne,NULL);

AfxBeginThread(FunTwo,NULL);

AfxBeginThread(GetResult,); //此时得到的值总是BBBB或者SSSS,哪一个线程拥有临界区不确定.只能保证某一个时间只能有一个线程拥有 }

//其它两个类也同样加上这两行代码

UINT FunOne(LPVOID pParam){

g_criSection.Lock()//给所有使用的资源上锁

for(int i =0; i < 4; i++){

g_charArray[i] = 'S';

Sleep(1);

}

g_criSection.UnLock(); //给使用的资源解锁

return 0;

}

其他线程同步的方法

使线程同步共有4种方法:

1.临界区(critical section)

2.事件(event)

3.信号量(Semaphore)

4.互拆量(Mutex)

其中1临界区是用户对象,所以没太多权限,只能处理同一个进程内的线程同步

而剩下的2,3,4都是内核对象,权限比较大,可以跨进程使用,因此能够处理不同进程间的线程同步问题.

其中的Mutext和临界区适用的场景基本上一样,只不过Mutext是内核对象,而critical section是用户对象

MFC线程(二):线程同步临界区CRITICAL SECTION的更多相关文章

  1. C#中的线程(二) 线程同步基础

    1.同步要领 下面的表格列展了.NET对协调或同步线程动作的可用的工具:                       简易阻止方法 构成 目的 Sleep 阻止给定的时间周期 Join 等待另一个线程 ...

  2. 第二十篇 .NET高级技术之C#中的线程(二) 线程同步基础

    1.同步要领 下面的表格列展了.NET对协调或同步线程动作的可用的工具:                       简易阻止方法 构成 目的 Sleep 阻止给定的时间周期 Join 等待另一个线程 ...

  3. 临界区(Critical Section)的封装和使用示例

    向我老大致敬! 这个做法其实是抄我老大的.服务器中,多线程经常需要使用临界区,为了简化代码的使用,把临界区封装为 CThreadLockHandle  类,通过封装,使用临界区资源每次只需要一行代码, ...

  4. win32多线程 (二)线程同步之临界区 (critical sections)

    所谓critical sections 意指一小块“用来处理一份被共享之资源”的程序代码.你可能必须在程序的许多地方处理这一块可共享的资源.所有这些程序代码可以被同一个critical  sectio ...

  5. MFC 多线程及线程同步

    一.MFC对多线程编程的支持 MFC中有两类线程,分别称之为工作者线程和用户界面线程.二者的主要区别在于工作者线程没有消息循环,而用户界面线程有自己的消息队列和消息循环. 工作者线程没有消息机制,通常 ...

  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线程(三):线程同步事件(event)与互斥(mutex)

    前面讲了临界区可以用来达到线程同步.而事件(event)与互斥(mutex)也同样可以做到. Win32 API中的线程事件 HANDLE hEvent = NULL; void MainTestFu ...

  8. MFC【17-2】线程和线程同步化

    17-2线程同步 Windows支持4中类型的同步对象,可以用过来同步由并发运行的线程执行的操作: 临界区 互斥量 事件 信号量 MFC在名为CCriticalSection\CMutex\CEven ...

  9. MFC多线程各种线程用法 .

    http://blog.csdn.net/qq61394323/article/details/9328301 一.问题的提出 编写一个耗时的单线程程序: 新建一个基于对话框的应用程序SingleTh ...

随机推荐

  1. Chisel3 - Tutorial - Functionality

    https://mp.weixin.qq.com/s/3hDzpJiANdwp07hO03psyA   演示使用函数进行代码复用的方法.   参考链接: https://github.com/ucb- ...

  2. 【Linux】文件权限,ssh免密登录

    1.文件/文件夹权限 例子: -rw-r--r--. 1 root root 12288 Aug 21 09:50 aliases.db drwxr-xr-x. 2 root root 4096 Au ...

  3. Java实现洛谷P1250 种树 (暴力)

    P1250 种树 输入输出样例 输入 9 4 1 4 2 4 6 2 8 9 2 3 5 2 输出 5 PS: 我种最少的树,意味着我的树要最多的被利用,意味着,我的树要尽可能的靠中间种, 也就是我把 ...

  4. Java实现 蓝桥杯 算法训练 最大的算式

    算法训练 最大的算式 时间限制:1.0s 内存限制:256.0MB 问题描述 题目很简单,给出N个数字,不改变它们的相对位置,在中间加入K个乘号和N-K-1个加号,(括号随便加)使最终结果尽量大.因为 ...

  5. 基于EntityFramework 6 Code First实现动态建库,分库,数据库自动迁移

    一.前言 公司原本有一个"xx系统",ORM使用EntityFramework,Code First模式.该系统是针对某个客户企业的,现要求该系统支持多个企业使用,但是又不能给每个 ...

  6. react使用Echarts绘制高亮可点击选中的省市地图

    最近做项目遇到一个需求,需要显示广东省各个地级市的地图,并且鼠标移入高亮显示,鼠标点击可以选中某个地级市.在网上查阅了大量资料之后,最后选择了使用echarts实现该需求.在此记录一下,希望可以帮到有 ...

  7. 认识OSI七层模型

    概述: OSI全名(Open System Interconnect),是指定的开放系统互连参考模型,为开放式互连信息系统提供了一种功能结构的框架.层次:从低到高的层级:物理层.数据链路层.网络层.传 ...

  8. 面试了 6 轮 Google 中国 之后,还是挂了

    去年换工作的时候, 面试了一下 Google (这里说的是 Google 中国哈), 来了个 Google 面试六轮游, 结果是没通过.

  9. Python 读取和输出到txt

    读txt文件 python常用的读取文件函数有三种read().readline().readlines() read() #一次性读取文本中全部的内容,以字符串的形式返回结果 with open(& ...

  10. vue2.0+Element UI 实现动态表单(点击按钮增删一排输入框)

    对于动态增减表单项,Element UI 官方文档表单那一节已经介绍得很清楚了,我之前没有看见,绕了很多弯路,这里针对点击按钮增删一排输入框的问题做一个总结. 效果图如下 存在一排必填的姓名与手机号, ...