写点什么

深究用户模式锁的使用场景 (异变结构、互锁、旋转锁)

作者:C++后台开发
  • 2022-11-30
    湖南
  • 本文字数:2614 字

    阅读完需:约 9 分钟

深究用户模式锁的使用场景(异变结构、互锁、旋转锁)

一. 锁机制的背景介绍

  本章节,将结合多线程来介绍锁机制, 那么问题来了,什么是锁呢? 为什么需要锁? 为什么要结合多线程来介绍锁呢?锁的使用场景又是什么呢? DotNet 中又有哪些锁呢?

  在接下来的几个章节中,将陆续解答这些问题。

PS:

多个线程对一个共享资源进行使用的时候,会出问题, 比如实际的业务场景,入库和出库操作同时进行,库存量就会存在并发问题。所以锁就是用来解决多线程资源竞用的问题。

Net 领域中,锁机制非常多,比如:时间锁、信号量、互斥锁、读写锁、互锁、异变结构,主要我们可以把他们划分为三大类:

①.用户模式锁:就是通过一些 cpu 指令或者一个死循环,来达到达到线程的等待和休眠。

②.内核模式锁:就是调用 win32 底层的代码,来实现 thread 的各种操作。

③.混合锁:用户模式+内核模式

  其中用户模式锁又分为这么几类:异变结构、互锁和旋转锁。

二. 异变结构

背景:一个线程读,一个线程写,在 release 模式下会出现 bug,导致主线程无法执行,原因在前面章节已经介绍过了。

  方式一:利用 MemoryBarrier 方法进行处理 。(前面章节已介绍)

  方式二:利用 VolatileRead/Write 方法进行处理。 (前面章节已介绍)

  方式三:volatile 关键字进行处理,我的 read 和 write 都是从 memrory 中读取,读取的都是最新的。(下面的案例使用 volatile 关键字后,主线程可以执行)

代码实践:

 1             public static volatile bool isStop = false; 2                 //使用Volatile关键字处理         3                 var t = new Thread(() => 4                 { 5                     var isSuccess = false; 6                     while (!isStop) 7                     { 8                         isSuccess = !isSuccess; 9                     }10                 });11                 t.Start();12                 Thread.Sleep(1000);13                 isStop = true;14                 t.Join();15                 Console.WriteLine("主线程执行结束!");16                 Console.ReadLine(); 
复制代码

代码结论:使用 volatile 关键字进行修饰,解决共享资源的竞用问题。

三. 互锁

  互锁结构(Interlocked 类),常用的方法有:

    * Increment:自增操作

    * Decrement:自减操作

    * Add: 增加指定的值

    * Exchange: 赋值

    * CompareExchange: 比较赋值

更多 C++后台开发技术点知识内容包括 C/C++,Linux,Nginx,ZeroMQ,MySQL,Redis,MongoDB,ZK,流媒体,音视频开发,Linux 内核,TCP/IP,协程,DPDK 多个高级知识点。

C/C++Linux服务器开发高级架构师/C++后台开发架构师​免费学习地址

【文章福利】另外还整理一些C++后台开发架构师 相关学习资料,面试题,教学视频,以及学习路线图,免费分享有需要的可以点击领取

代码实践:

 1             { 2                 //1. 自增 3                 { 4                     int a = 1; 5                     Interlocked.Increment(ref a); 6                     Console.WriteLine("自增后的数据为:{0}", a); 7                 } 8                 //2. 自减 9                 {10                     int b = 2;11                     Interlocked.Decrement(ref b);12                     Console.WriteLine("自减后的数据为:{0}", b);13                 }14                 //3. 增加操作15                 {16                     int c = 3;17                     Interlocked.Add(ref c, 4);18                     Console.WriteLine("增加后的数据为:{0}", c);19 20                 }21                 //4. 赋值操作22                 {23                     int d = 4;24                     Interlocked.Exchange(ref d, 55);25                     Console.WriteLine("赋值后的数据为:{0}", d);26 27                 }28                 //5. 比较赋值29                 {30                     //Interlocked.CompareExchange(ref num1, sum, num2);  // num1==num2 ; num1=sum;31                     int ee = 5;32                     Interlocked.CompareExchange(ref ee, 15, 5);33                     Console.WriteLine("比较赋值后的数据为:{0}", ee);34 35                     Interlocked.CompareExchange(ref ee, 100, 15);36                     Console.WriteLine("比较赋值后的数据为:{0}", ee);37 38                 }39 40             }
复制代码

代码结果:

​四. 旋转锁

  旋转锁(SpinLock), 特殊的业务逻辑让 thread 在用户模式下进行自选,欺骗 cpu 当前 thread 正在运行中。

 SpinLock 类有两个核心方法,分别是:Enter 和 Exit 方法。

代码实践:

 1             { 2                 //下面代码的结果:num从0-249,且是有序的。 3                 //如果把旋转锁去掉,num将没有任何顺序 4                 for (int i = 0; i < 5; i++) 5                 { 6                     Task.Factory.StartNew(() => 7                     { 8                         for (int j = 0; j < 50; j++) 9                         {10                             try11                             {12                                 var b = false;13                                 sl.Enter(ref b);14                                 Console.WriteLine(num++);15                             }16                             catch (Exception ex)17                             {18                                 Console.WriteLine(ex.Message);19                             }20                             finally21                             {22                                 sl.Exit();23                             }24                         }25                     });26                 }27             }
复制代码

代码结果:下面代码的结果:num 从 0-249,且是有序的;如果将旋转锁的代码去掉,num 的输出将没有任何顺序可言。


原文链接:第十一节:深究用户模式锁的使用场景(异变结构、互锁、旋转锁) - Yaopengfei - 博客园

用户头像

C/C++后台开发技术交流qun:720209036 2022-05-06 加入

还未添加个人简介

评论

发布
暂无评论
深究用户模式锁的使用场景(异变结构、互锁、旋转锁)_数据结构_C++后台开发_InfoQ写作社区