博客
关于我
Windows 临界区(CRITICAL_SECTION)的使用
阅读量:662 次
发布时间:2019-03-14

本文共 2326 字,大约阅读时间需要 7 分钟。

由于需要在多线程中并发操作临界数据,为了保证临界数据操作的完整性,Linux下使用锁(Linux下锁可以看我的这篇博客),而在Windows下,使用的是临界区。

每个线程中访问临界资源的那段程序称为临界区(Critical Section)(临界资源是一次仅允许一个线程使用的共享资源)。每次只准许一个线程进入临界区,进入后不允许其他线程进入。不论是硬件临界资源,还是软件临界资源,多个线程必须互斥地对它进行访问。在说临界区之前,我们先讲下同步和互斥,以理解为什么需要临界区。

 


同步和互斥机制

  • 基本概念

同步和互斥的概念有时候很容易混淆,可以简单地认为同步是更加宏观角度的一种说法,互斥是冲突解决的细节方法。所谓同步就是调度者让任务按照约定的合理的顺序进行,但是当任务之间出现资源竞争,也就是竞态冲突时,使用互斥的规则强制约束允许数量的任务占用资源,从而解决各个竞争状态,实现任务的合理运行。

同步和互斥密不可分,有资料说互斥是一种特殊的同步,对此我不太理解,不过实际中想明白细节就行,文字游戏没有意义。

简单来说:

  • 同步与互斥机制是用于控制多个任务对某些特定资源的访问策略
  • 同步是控制多个任务按照一定的规则或顺序访问某些共享资源
  • 互斥是控制某些共享资源在任意时刻只能允许规定数量的任务访问
  • 角色分类

整个协调流程涉及的角色本质上只有三类:

  • 不可独占的共享资源
  • 多个使用者
  • 调度者

调度者需要为多个运行任务制定访问使用规则来实现稳定运行,这个调度者可以是内核、可以是应用程序,具体场景具体分析。

  • 重要术语

要很好地理解同步和互斥,就必须得搞清楚几个重要术语:

  • 竞争冒险(race hazard)或竞态条件(race condition)

最早听说这个术语是在模电数电的课程上,门电路出现竞态条件造成错误的结果,在计算机里面就是多个使用者同时操作共享的变量造成结果的不确定。

  • 临界区

临界区域critical section是指多使用者可能同时共同操作的那部分代码,比如自加自减操作,多个线程处理时就需要对自加自减进行保护,这段代码就是临界区域。

 


 临界区(Critical Section)

Linux下有递归锁,递归锁是同一个线程在不解锁的情况下,可以多次获取锁定同一个递归锁,而且不会产生死锁。windows下的互斥量和临界区(关键段)默认支持递归锁。

  • void InitializeCriticalSection(  LPCRITICAL_SECTION lpCriticalSection);初始化一个临界区对象
  • void DeleteCriticalSection(_Inout_ LPCRITICAL_SECTION lpCriticalSection);删除临界区对象释放由该对象使用的所有系统资源

  • void EnterCriticalSection( LPCRITICAL_SECTION lpCriticalSection );//进入临界区,相当于Linux下lock

  • void LeaveCriticalSection( LPCRITICAL_SECTION lpCriticalSection );//删除临界区,相当于Linux下unlock

#include 
#include
#include
​int counter = 0;​// 定义一个临界区变量CRITICAL_SECTION g_cs;​void doit(void* arg){ int i, val; for (i=0; i<5000; i++) { // 临界区默认支持递归锁,所以这里在临界区里再次进入临界区也没关系,正常使用调用一次即可 EnterCriticalSection(&g_cs); EnterCriticalSection(&g_cs);​ val = counter; printf("thread %d : %d\n", int(arg), val+1); counter = val + 1;​ // 离开临界区 LeaveCriticalSection(&g_cs); LeaveCriticalSection(&g_cs); }}​int main(int argc, char*argv[]){ // 初始化临界区 InitializeCriticalSection(&g_cs);​ HANDLE hThread1 = CreateThread(NULL,0, (LPTHREAD_START_ROUTINE)doit, (void*)1, 0, NULL); HANDLE hTrehad2 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)doit, (void*)2, 0, NULL);​ WaitForSingleObject(hThread1, INFINITE); WaitForSingleObject(hTrehad2, INFINITE);​ // 删除临界区 DeleteCriticalSection(&g_cs);​ return 0;}

使用临界区加1次锁和2次锁,均可以正确的输出1~10000。

 

转载地址:http://phulz.baihongyu.com/

你可能感兴趣的文章
ngrok内网穿透可以实现资源共享吗?快解析更加简洁
查看>>
NHibernate动态添加表
查看>>
NHibernate学习[1]
查看>>
NHibernate异常:No persister for的解决办法
查看>>
Nhibernate的第一个实例
查看>>
NHibernate示例
查看>>
nid修改oracle11gR2数据库名
查看>>
NIFI1.21.0/NIFI1.22.0/NIFI1.24.0/NIFI1.26.0_2024-06-11最新版本安装_采用HTTP方式_搭建集群_实际操作---大数据之Nifi工作笔记0050
查看>>
NIFI1.21.0_java.net.SocketException:_Too many open files 打开的文件太多_实际操作---大数据之Nifi工作笔记0051
查看>>
NIFI1.21.0_Mysql到Mysql增量CDC同步中_日期类型_以及null数据同步处理补充---大数据之Nifi工作笔记0057
查看>>
NIFI1.21.0_Mysql到Mysql增量CDC同步中_补充_插入时如果目标表中已存在该数据则自动改为更新数据_Postgresql_Hbase也适用---大数据之Nifi工作笔记0058
查看>>
NIFI1.21.0_Mysql到Mysql增量CDC同步中_补充_更新时如果目标表中不存在记录就改为插入数据_Postgresql_Hbase也适用---大数据之Nifi工作笔记0059
查看>>
NIFI1.21.0_NIFI和hadoop蹦了_200G集群磁盘又满了_Jps看不到进程了_Unable to write in /tmp. Aborting----大数据之Nifi工作笔记0052
查看>>
NIFI1.21.0_Postgresql和Mysql同时指定库_指定多表_全量同步到Mysql数据库以及Hbase数据库中---大数据之Nifi工作笔记0060
查看>>
NIFI1.21.0最新版本安装_连接phoenix_单机版_Https登录_什么都没改换了最新版本的NIFI可以连接了_气人_实现插入数据到Hbase_实际操作---大数据之Nifi工作笔记0050
查看>>
NIFI1.21.0最新版本安装_配置使用HTTP登录_默认是用HTTPS登录的_Https登录需要输入用户名密码_HTTP不需要---大数据之Nifi工作笔记0051
查看>>
NIFI1.21.0通过Postgresql11的CDC逻辑复制槽实现_指定表多表增量同步_增删改数据分发及删除数据实时同步_通过分页解决变更记录过大问题_02----大数据之Nifi工作笔记0054
查看>>
NIFI1.21.0通过Postgresql11的CDC逻辑复制槽实现_指定表多表增量同步_增加修改实时同步_使用JsonPath及自定义Python脚本_03---大数据之Nifi工作笔记0055
查看>>
NIFI1.21.0通过Postgresql11的CDC逻辑复制槽实现_指定表多表增量同步_插入修改删除增量数据实时同步_通过分页解决变更记录过大问题_01----大数据之Nifi工作笔记0053
查看>>
NIFI1.21.0通过Postgresql11的CDC逻辑复制槽实现_指定表或全表增量同步_实现指定整库同步_或指定数据表同步配置_04---大数据之Nifi工作笔记0056
查看>>