.net core WebApi Interlocked配合ManualResetEventSlim实现并发同步

42 篇文章 0 订阅
8 篇文章 0 订阅

https://blog.csdn.net/dietisi8980/article/details/101856688

由于项目有某种需求,在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()的作用是让当前事件对象拥有信号量,可以让当前线程继续执行。

转载于:https://www.cnblogs.com/williamwsj/p/9702340.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在ASP.NET Core C#中,可以使用System.Threading.Tasks.Task类来创建和管理线程池。以下是一个简单的线程池实现: ```csharp using System; using System.Collections.Generic; using System.Linq; using System.Threading; using System.Threading.Tasks; namespace ThreadPoolDemo { public class MyThreadPool { private readonly Queue<Action> _tasks = new Queue<Action>(); private readonly object _lock = new object(); private readonly int _maxThreads; private int _runningThreads = 0; private bool _disposed = false; public MyThreadPool(int maxThreads) { _maxThreads = maxThreads; } public void QueueTask(Action task) { if (_disposed) { throw new ObjectDisposedException(nameof(MyThreadPool)); } lock (_lock) { _tasks.Enqueue(task); if (_runningThreads < _maxThreads) { Interlocked.Increment(ref _runningThreads); Task.Factory.StartNew(ExecuteTask, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); } } } private void ExecuteTask() { while (true) { Action task = null; lock (_lock) { if (_tasks.Count > 0) { task = _tasks.Dequeue(); } else { Interlocked.Decrement(ref _runningThreads); break; } } task(); } } public void Dispose() { if (_disposed) { return; } _disposed = true; lock (_lock) { while (_tasks.Count > 0) { var task = _tasks.Dequeue(); } _runningThreads = 0; } } } } ``` 使用示例: ```csharp using System; namespace ThreadPoolDemo { class Program { static void Main(string[] args) { using (var pool = new MyThreadPool(4)) { for (int i = 0; i < 10; i++) { var index = i; pool.QueueTask(() => Console.WriteLine($"Task {index} is running on thread {Thread.CurrentThread.ManagedThreadId}")); } } } } } ``` 这个线程池实现使用一个队列来存储待执行的任务。当有新的任务加入队列时,它会检查当前运行的线程数量是否已经达到最大值,如果没有,则创建新的线程来执行任务。当所有任务执行完毕时,线程池会自动关闭所有线程。 请注意,这个线程池实现只是一个简单的示例,没有考虑到一些高级功能,例如线程异常处理、任务取消等。在实际应用中,需要根据实际需求进行完善。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值