zoukankan      html  css  js  c++  java
  • .net core WebApi Interlocked配合ManualResetEventSlim实现并发同步

    由于项目有某种需求,在WebApi中,有大量的请求需要操作相同的数据,因此需要用到并发同步机制去操作共享的数据。

    本次配合使用Interlocked和ManualResetEventSlim来实现并发同步的目的。

    Interlocked实现了原子性的操作,ManualResetEventSlim提供信号量等待唤醒机制。

    以上两个关键字,自行找度娘了解。

    代码如下:

            [HttpGet("[controller]/v1/api/[action]")]
            public IActionResult Test() {
                return Json(SynchronizationTest());
            }
    
            protected static int Counter = 1;//1:空闲 0:非空闲
            protected static ManualResetEventSlim Mres = new ManualResetEventSlim(false);
            public ResponseModel SynchronizationTest() {
                ResponseModel rc = new ResponseModel(0, "初始化");
               
                try {
    //重置信号量,相当于灭灯
    Mres.Reset();
    //如果其他线程正在操作,则等待,5秒后超时 if (Interlocked.CompareExchange(ref Counter, 0, 1) == 0) Mres.Wait(5000); int count = RedisHelper.Get(GoodsNumberKey).ToInt32(); if (count > 0) { RedisHelper.Set(GoodsNumberKey, "-1"); rc.SetMessage("重置成功!"); } else rc.SetMessage("已被重置,本次重置无效"); } catch (Exception ex) { _log.Error(ex); } finally { //转为空闲状态 Interlocked.Exchange(ref Counter, 1); //设置信号量,让上面的 Mres.Wait(5000);取消等待,继续执行代码。相当于亮灯 Mres.Set(); } return rc; }

    逻辑是:如果Counter为0(非空闲),则证明已经有其他线程先一步进入当前逻辑,则当前线程需要等待5秒钟(5秒钟超时后继续执行代码),finally中的代码表示执行完后会将Counter置为1(空闲)并唤醒其他等待的线程,让其他线程在超时之前继续执行。

    注意:信号量事件(ManualResetEventSlim)对象要用同一个的Wait、Reset和Set配合才会实现并发同步的效果。

    相关代码解释:

    Interlocked.CompareExchange(ref int number,int firstValue,int secondValue);该方法一共有三个参数,作用是:如果number和secondValue相等,则将firstValue引用赋值给number,否则不做任何操作,之后会返回number的原始值。参考如下代码:

    int tmp = number;
    ref number = number==secondValue?firstValue:number;
    return tmp;

    Interlocked.Exchange(ref int number,int value)的作用是将value引用赋值给number,并返回number的原始值。

    ManualResetEventSlim Mres = new ManualResetEventSlim(false),ManualResetEventSlim的构造函数,如果参数为true,则当前对象拥有信号量,如果为false,则不拥有信号量。ManualResetEventSlim的作用就是通过信号量的判别,是否阻塞当前线程。如果不拥有信号量,则Wait()方法可以让当前线程阻塞,一旦拥有了信号量,就结束Wait()方法的执行,并沿着当前代码继续执行下去。

    ManualResetEventSlim.Reset()的作用是释放当前事件对象的信号量,接着调用其Wait()方法会阻塞当前线程。

    ManualResetEventSlim.Set()的作用是让当前事件对象拥有信号量,可以让当前线程继续执行。

  • 相关阅读:
    VS2005 中关于“LC.EXE已退出,代码为 1”的错误解决方法。
    由于目标机器积极拒绝,无法连接。
    What is Android?
    利用批处理文件和任务计划实现Oracle数据库的自动备份
    就差了一点点....
    由Login.aspx引发编译器错误的解决方法
    都是补丁惹的祸...
    终于结束了
    GIS当然可以很酷
    rar.exe命令行参数与示例
  • 原文地址:https://www.cnblogs.com/williamwsj/p/9702340.html
Copyright © 2011-2022 走看看