CRITICAL_SECTION用法案例详解

      很多人对CRITICAL_SECTION的理解是错误的,认为CRITICAL_SECTION是锁定了资源,其实,CRITICAL_SECTION是不能够“锁定”资源的,它能够完成的功能,是同步不同线程的代码段。简单说,当一个线程执行了EnterCritialSection之后,cs里面的信息便被修改,以指明哪一个线程占用了它。而此时,并没有任何资源被“锁定”。不管什么资源,其它线程都还是可以访问的(当然,执行的结果可能是错误的)。只不过,在这个线程尚未执行LeaveCriticalSection之前,其它线程碰到EnterCritialSection语句的话,就会处于等待状态,相当于线程被挂起了。 这种情况下,就起到了保护共享资源的作用。

      也正由于CRITICAL_SECTION是这样发挥作用的,所以,必须把每一个线程中访问共享资源的语句都放在EnterCritialSection和LeaveCriticalSection之间。这是初学者很容易忽略的地方。

      当然,上面说的都是对于同一个CRITICAL_SECTION而言的。 如果用到两个CRITICAL_SECTION,比如说:

第一个线程已经执行了EnterCriticalSection(&cs)并且还没有执行LeaveCriticalSection(&cs),这时另一个线程想要执行EnterCriticalSection(&cs2),这种情况是可以的(除非cs2已经被第三个线程抢先占用了)。这也就是多个CRITICAL_SECTION实现同步的思想。

       比如说我们定义了一个共享资源dwTime[100],两个线程ThreadFuncA和ThreadFuncB都对它进行读写操作。当我们想要保证 dwTime[100]的操作完整性,即不希望写到一半的数据被另一个线程读取,那么用CRITICAL_SECTION来进行线程同步如下:

      第一个线程函数:

DWORD WINAPI ThreadFuncA(LPVOID lp)
{
            EnterCriticalSection(&cs);
            ...
            //   操作dwTime
            ...
            LeaveCriticalSection(&cs);
            return   0;
}

       写出这个函数之后,很多初学者都会错误地以为,此时cs对dwTime进行了锁定操作,dwTime处于cs的保护之中。一个“自然而然”的想法就是——cs和dwTime一一对应上了。这么想,就大错特错了。dwTime并没有和任何东西对应,它仍然是任何其它线程都可以访问的。
如果你像如下的方式来写第二个线程,那么就会有问题:

DWORD   WINAPI   ThreadFuncB(LPVOID   lp)
{
            ...
            //   操作dwTime
            ...
            return   0;
}

      当线程ThreadFuncA执行了EnterCriticalSection(&cs),并开始操作dwTime[100]的时候,线程ThreadFuncB可能随时醒过来,也开始操作dwTime[100],这样,dwTime[100]中的数据就被破坏了。

      为了让 CRITICAL_SECTION发挥作用,我们必须在访问dwTime的任何一个地方都加上 EnterCriticalSection(&cs)和LeaveCriticalSection(&cs)语句。所以,必须按照下面的方式来写第二个线程函数:

DWORD   WINAPI   ThreadFuncB(LPVOID   lp)
{
            EnterCriticalSection(&cs);
            ...
            //   操作dwTime
            ...
            LeaveCriticalSection(&cs);
            return   0;
}

      这样,当线程ThreadFuncB醒过来时,它遇到的第一个语句是EnterCriticalSection(&cs),这个语句将对cs变量进行访问。如果这个时候第一个线程仍然在操作dwTime[100],cs变量中包含的值将告诉第二个线程,已有其它线程占用了cs。因此,第二个线程的 EnterCriticalSection(&cs)语句将不会返回,而处于挂起等待状态。直到第一个线程执行了 LeaveCriticalSection(&cs),第二个线程的EnterCriticalSection(&cs)语句才会返回,并且继续执行下面的操作。

      这个过程实际上是通过限制有且只有一个函数进入CriticalSection变量来实现代码段同步的。简单地说,对于同一个CRITICAL_SECTION,当一个线程执行了EnterCriticalSection而没有执行 LeaveCriticalSection的时候,其它任何一个线程都无法完全执行EnterCriticalSection而不得不处于等待状态。

      再次强调一次,没有任何资源被“锁定”,CRITICAL_SECTION这个东东不是针对于资源的,而是针对于不同线程间的代码段的!我们能够用它来进行所谓资源的“锁定”,其实是因为我们在任何访问共享资源的地方都加入了EnterCriticalSection和 LeaveCriticalSection语句,使得同一时间只能够有一个线程的代码段访问到该共享资源而已(其它想访问该资源的代如果是两个CRITICAL_SECTION,就以此类推。码段不得不等待)。
如果是两个CRITICAL_SECTION,就以此类推。

再举个极端的例子,可以帮助你理解CRITICAL_SECTION这个东东:
第一个线程函数:

DWORD   WINAPI   ThreadFuncA(LPVOID   lp)
{
            EnterCriticalSection(&cs);
            for(int   i=0;i <1000;i++)
                        Sleep(1000);
            LeaveCriticalSection(&cs);
            return   0;
}

第二个线程函数:

DWORD   WINAPI   ThreadFuncB(LPVOID   lp)
{
            EnterCriticalSection(&cs);
            index=2;
            LeaveCriticalSection(&cs);
            return   0;
}

      这种情况下,第一个线程中间总共Sleep了1000秒钟!它显然没有对任何资源进行什么“有意识”的保护;而第二个线程是要访问资源index的,但是由于第一个线程占用了cs,一直没有Leave,而导致第二个线程不得不等上1000秒钟……
第二个线程,真是可怜啊!
这个应该很说明问题了,你会看到第二个线程在1000秒钟之后开始执行index=2这个语句。也就是说,CRITICAL_SECTION其实并不理会你关心的具体共享资源,它只按照自己的规律办事~

到此这篇关于CRITICAL_SECTION用法案例详解的文章就介绍到这了,更多相关CRITICAL_SECTION用法内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++ EnterCriticalSection简单使用

    目录 EnterCriticalSection作用 一.首先是它的使用步骤: 二.示例代码: EnterCriticalSection作用 用途主要是在多线程中,当开启多线程中,要控制函数的执行顺序时,就需要用到它了,就是假如多个线程同时访问这个函数时,需要控制执行的顺序,可以使用它去控制顺序. 定义一个全局的锁 CRITICAL_SECTION的实例 和一个静态全局变量 CRITICAL_SECTION cs;//可以理解为锁定一个资源 static int n_AddValue = 0;//

  • C++使用CriticalSection实现线程同步实例

    本文实例讲述了C++使用CriticalSection实现线程同步的方法,在前文C++线程同步实例分析的基础上增加了四行代码,使用了四个函数: EnterCriticalSection ::DeleteCriticalSection ::EnterCriticalSection ::LeaveCriticalSection此时,打印出来的数字就相等了. 具体代码如下: #include "stdafx.h" #include <Windows.h> DWORD g_cnt1

  • IDEA遇到Internal error. Please refer to http://jb. gg/ide/critical-startup-errors的问题及解决办法

    今天打算把原本的2018的idea升个级,安一个2020 的idea试试各种新插件,但遇到了很多问题,比如安装后打不开,好不容易打开了然后报错 Internal error. Please refer to http://jb. gg/ide/critical-startup-errors  ... Caused by: java. lang. ClasslotFoundException: com rover12421. crack. jetbrains. v2. Util at com in

  • spring cloud consul注册的服务报错critical的解决

    测试spring cloud 使用consul注册服务的时候,出现critical,如下: 怎么解决这个问题,现在只能看到health check检查失败了. 受限调用这个请求Get http://consulIp:8500/v1/agent/checks,调完请求,就会拿到返回数据: { ...... "service:test-service-xx-xx-xx-xx": { "Node": "zookeeper-server1", "

  • CRITICAL_SECTION用法案例详解

          很多人对CRITICAL_SECTION的理解是错误的,认为CRITICAL_SECTION是锁定了资源,其实,CRITICAL_SECTION是不能够"锁定"资源的,它能够完成的功能,是同步不同线程的代码段.简单说,当一个线程执行了EnterCritialSection之后,cs里面的信息便被修改,以指明哪一个线程占用了它.而此时,并没有任何资源被"锁定".不管什么资源,其它线程都还是可以访问的(当然,执行的结果可能是错误的).只不过,在这个线程尚未执

  • C语言 CRITICAL_SECTION用法案例详解

          很多人对CRITICAL_SECTION的理解是错误的,认为CRITICAL_SECTION是锁定了资源,其实,CRITICAL_SECTION是不能够"锁定"资源的,它能够完成的功能,是同步不同线程的代码段.简单说,当一个线程执行了EnterCritialSection之后,cs里面的信息便被修改,以指明哪一个线程占用了它.而此时,并没有任何资源被"锁定".不管什么资源,其它线程都还是可以访问的(当然,执行的结果可能是错误的).只不过,在这个线程尚未执

  • Python中return用法案例详解

    python中return的用法 1.return语句就是把执行结果返回到调用的地方,并把程序的控制权一起返回 程序运行到所遇到的第一个return即返回(退出def块),不会再运行第二个return. 例如: def haha(x,y): if x==y: return x,y print(haha(1,1)) 已改正: 结果:这种return传参会返回元组(1, 1) 2.但是也并不意味着一个函数体中只能有一个return 语句,例如: def test_return(x): if x >

  • Java ConcurrentHashMap用法案例详解

    一.概念 哈希算法(hash algorithm):是一种将任意内容的输入转换成相同长度输出的加密方式,其输出被称为哈希值. 哈希表(hash table):根据设定的哈希函数H(key)和处理冲突方法将一组关键字映象到一个有限的地址区间上,并以关键字在地址区间中的象作为记录在表中的存储位置,这种表称为哈希表或散列,所得存储位置称为哈希地址或散列地址. 二.HashMap与HashTable 1,线程不安全的HashMap 因为多线程环境下,使用HashMap进行put操作会引起死循环,导致CP

  • C++优先队列用法案例详解

    c++优先队列(priority_queue)用法详解 普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除. 在优先队列中,元素被赋予优先级.当访问元素时,具有最高优先级的元素最先删除.优先队列具有最高级先出 (first in, largest out)的行为特征. 首先要包含头文件#include<queue>, 他和queue不同的就在于我们可以自定义其中数据的优先级, 让优先级高的排在队列前面,优先出队. 优先队列具有队列的所有特性,包括队列的基本操作,只是在这基础上

  • CSS hack用法案例详解

    之前一直很狭隘的对CSS hack持有偏见,觉得写得规范的代码不应该使用这些"邪门歪道",可最近产品发布一个小问题却让我头疼了很久,最后查了一下资料,竟然使用CSS hack轻松解决了,不得不服啊,对付神奇的IE就得使用这些利器. 什么是CSS hack 由于不同的浏览器,甚至同一浏览器的不同版本对CSS的解析认识不一样,导致生成的页面效果不一致,写出针对不同浏览器CSS code就称为CSS hack. 常用的CSS hack 有三种方式,CSS 内部hack.选择器hack.HTM

  • C# Request.Form用法案例详解

    在CS文件中获得对应页面中的下拉框DropDownList_sitebranch值可以有以下几种方法获得: siteInfo.FZJGID = DropDownList_sitebranch.SelectedItem.Value.Trim(); siteInfo.FZJGID = Request.Form["DropDownList_sitebranch"].ToString(); siteInfo.FZJGID = Request["DropDownList_sitebra

  • C++ ostream用法案例详解

    概述 在 C++中,ostream表示输出流,英文"output stream"的简称.在 C++中常见的输出流对象就是标准输出流cout,很少自定义ostream的对象,更多的是直接使用cout.那么 ostream 有什么用呢,来看一个场景: class CPoint { public: CPoint(int x_,int y_):x(x_),y(y_){} int x,y; }; 这里定义了一个简单的类CPoint,如果我们实例化该类过后,想要打印对象的值: CPoint poi

  • C# Console.WriteLine()用法案例详解

    以前用Console.WriteLine()的时候就只会用它直接输出string字符串,但后来发现它还有其它在有些场合下会十分方便的输出方法,这篇就记录一下这些方法的使用吧. 代码格式我就不写了,因为写了也不好理解,所以直接上示例了.  ① static void Main(string[] args) { int i = 6; string s = "输出"; Console.WriteLine("{0}还可以这样{1}哦.", i, s); Console.Wr

  • MFC LoadImage用法案例详解

    目录 函数原型 cxDesired, cyDesired: fuLoad: 示例 1.加载Icon资源 2.加载本地磁盘的Icon文件 3.加载本地磁盘的Bitmap文件 函数原型 HANDLE LoadImage( HINSTANCE hinst, // 若加载程序外部资源传NULL,否则一般传AfxGetInstanceHandle() LPCTSTR lpszName, // 图片名称或全路径 UINT uType, // 图片类型:IMAGE_BITMAP或IMAGE_ICON或IMAG

随机推荐