博客
关于我
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/

你可能感兴趣的文章
logstash mysql 准实时同步到 elasticsearch
查看>>
Luogu2973:[USACO10HOL]赶小猪
查看>>
mabatis 中出现&lt; 以及&gt; 代表什么意思?
查看>>
Mac book pro打开docker出现The data couldn’t be read because it is missing
查看>>
MAC M1大数据0-1成神篇-25 hadoop高可用搭建
查看>>
mac mysql 进程_Mac平台下启动MySQL到完全终止MySQL----终端八步走
查看>>
Mac OS 12.0.1 如何安装柯美287打印机驱动,刷卡打印
查看>>
MangoDB4.0版本的安装与配置
查看>>
Manjaro 24.1 “Xahea” 发布!具有 KDE Plasma 6.1.5、GNOME 46 和最新的内核增强功能
查看>>
mapping文件目录生成修改
查看>>
MapReduce程序依赖的jar包
查看>>
mariadb multi-source replication(mariadb多主复制)
查看>>
MariaDB的简单使用
查看>>
MaterialForm对tab页进行隐藏
查看>>
Member var and Static var.
查看>>
memcached高速缓存学习笔记001---memcached介绍和安装以及基本使用
查看>>
memcached高速缓存学习笔记003---利用JAVA程序操作memcached crud操作
查看>>
Memcached:Node.js 高性能缓存解决方案
查看>>
memcache、redis原理对比
查看>>
memset初始化高维数组为-1/0
查看>>