原文:http://www.yalongyang.com/2013/01/c-sharp-await-lock/

在C#中,普通用锁很简单

  1. object m_lock = new object();
  2. lock(m_lock)
  3. {
  4. ......
  5. }

其中 ...... 表示互斥的代码。
这样就可以保证同时仅会有一个地方在执行这段互斥代码。

然而如果互斥代码中由await调用,上面的方式就行不通了,由于普通的lock代码段中无法存在await调用。

但是在实际使用中,经常遇见需要保护互斥的await情况,
比如用 await FileIO.WriteTextAsync() 的调用写文件,需要保证同时仅有一个地方在调用此段代码,不然就会出现互斥错误。

以下两篇文章很好的说明了如何实现对await调用互斥的处理。

可以总结为以下代码

  1. class AsyncSemaphore
  2. {
  3. private readonly static Task s_completed = Task.FromResult(true);
  4. private readonly Queue<TaskCompletionSource<bool>> m_waiters = new Queue<TaskCompletionSource<bool>>();
  5. private int m_currentCount;
  6.  
  7. public AsyncSemaphore(int initialCount)
  8. {
  9. if (initialCount < ) throw new ArgumentOutOfRangeException("initialCount");
  10. m_currentCount = initialCount;
  11. }
  12.  
  13. public Task WaitAsync()
  14. {
  15. lock (m_waiters)
  16. {
  17. if (m_currentCount > )
  18. {
  19. --m_currentCount;
  20. return s_completed;
  21. }
  22. else
  23. {
  24. var waiter = new TaskCompletionSource<bool>();
  25. m_waiters.Enqueue(waiter);
  26. return waiter.Task;
  27. }
  28. }
  29. }
  30.  
  31. public void Release()
  32. {
  33. TaskCompletionSource<bool> toRelease = null;
  34. lock (m_waiters)
  35. {
  36. if (m_waiters.Count > )
  37. toRelease = m_waiters.Dequeue();
  38. else
  39. ++m_currentCount;
  40. }
  41. if (toRelease != null)
  42. toRelease.SetResult(true);
  43. }
  44. }
  45.  
  46. public class AsyncLock
  47. {
  48. private readonly AsyncSemaphore m_semaphore;
  49. private readonly Task<Releaser> m_releaser;
  50.  
  51. public AsyncLock()
  52. {
  53. m_semaphore = new AsyncSemaphore();
  54. m_releaser = Task.FromResult(new Releaser(this));
  55. }
  56.  
  57. public Task<Releaser> LockAsync()
  58. {
  59. var wait = m_semaphore.WaitAsync();
  60. return wait.IsCompleted ?
  61. m_releaser :
  62. wait.ContinueWith((_, state) => new Releaser((AsyncLock)state),
  63. this, CancellationToken.None,
  64. TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
  65. }
  66.  
  67. public struct Releaser : IDisposable
  68. {
  69. private readonly AsyncLock m_toRelease;
  70.  
  71. internal Releaser(AsyncLock toRelease) { m_toRelease = toRelease; }
  72.  
  73. public void Dispose()
  74. {
  75. if (m_toRelease != null)
  76. m_toRelease.m_semaphore.Release();
  77. }
  78. }
  79. }

调用时仅需要:

  1. readonly AsyncLock m_lock = new AsyncLock();
  2. using (var releaser = await m_lock.LockAsync())
  3. {
  4. await FileIO.WriteTextAsync(configureFile, jsonString);
  5. }

C# 异步锁【转】的更多相关文章

  1. 使用Nito.AsyncEx实现异步锁(转)

    转载地址:http://www.cnblogs.com/1zhk/p/5269279.html Lock是常用的同步锁,但是我们无法在Lock的内部实现异步调用,比如我们无法使用await. 以下面的 ...

  2. 使用Nito.AsyncEx实现异步锁

    Lock是常用的同步锁,但是我们无法在Lock的内部实现异步调用,比如我们无法使用await. 以下面的代码为例,当你在lock内部使用await时,VS会报错提醒. 最简单的解决办法就是使用第三方的 ...

  3. C# 异步锁 await async锁,lock,Monitor,SemaphoreSlim

    异步方法内无法使用Monitor 和lock 所以只能用System.Threading.SemaphoreSlim了 //Semaphore (int initialCount, int maxim ...

  4. C# 异步锁

    参考网址: https://www.cnblogs.com/Alicia-meng/p/13330640.html 使用SemaphoreSlim 实现 当多个任务或线程并行运行时,难以避免的对某些有 ...

  5. C#异步编程(五)异步的同步构造

    异步的同步构造 任何使用了内核模式的线程同步构造,我都不是特别喜欢.因为所有这些基元都会阻塞一个线程的运行.创建线程的代价很大.创建了不用,这于情于理说不通. 创建了reader-writer锁的情况 ...

  6. C# 并发编程 (异步编程与多线程)

    并发:同时做多件事情 多线程:并发的一种形式,它采用多个线程来执行程序. 并行处理:把正在执行的大量的任务分割成小块,分配给多个同时运行的线程.并行处理是多线程的一种,而多线程是并发的一种. 异步编程 ...

  7. zk客户端及锁的使用

    1.生成zk客户端对象 private CuratorFramework buildClient() { logger.info("zookeeper registry center ini ...

  8. 单元测试NUnit,mock组件NSubstitute,信号量SemaphoreSlim,异步lock等例子

    public class LockTest { private IDatabase _database; private readonly Random _random = new Random(); ...

  9. 【Oracle 集群】ORACLE DATABASE 11G RAC 知识图文详细教程之RAC 工作原理和相关组件(三)

    RAC 工作原理和相关组件(三) 概述:写下本文档的初衷和动力,来源于上篇的<oracle基本操作手册>.oracle基本操作手册是作者研一假期对oracle基础知识学习的汇总.然后形成体 ...

随机推荐

  1. JAVA-JSP内置对象之session对象设置并获得session生命周期

    相关资料:<21天学通Java Web开发> session对象设置并获得session生命周期1.通过session对象的setMaxInactiveInterval()方法可以设置se ...

  2. 2. AutoEncoder在NLP中的应用

    1. AutoEncoder介绍 2. Applications of AutoEncoder in NLP 3. Recursive Autoencoder(递归自动编码器) 4. Stacked ...

  3. 收藏mac重装php环境

    参考网址: 全新安装Mac OSX 开发者环境 同时使用homebrew搭建 PHP,Nginx ,MySQL,Redis,Memcache ... ... (LNMP开发环境)

  4. Selenium (3) —— Selenium IDE + Firefox录制登录脚本(101 Tutorial)

    Selenium (3) -- Selenium IDE + Firefox录制登录脚本(101 Tutorial) selenium IDE版本: 2.9.1 firefox版本: 39.0.3 参 ...

  5. hbase源码系列(六)HMaster启动过程

    这一章是server端开始的第一章,有兴趣的朋友先去看一下hbase的架构图,我专门从网上弄下来的. 按照HMaster的run方法的注释,我们可以了解到它的启动过程会去做以下的动作. * <l ...

  6. 【C】——信号量 互斥锁 条件变量的区别

    信号量用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作(大家都在semtake的时候,就阻塞在哪里).而互斥锁是用在多线程多任务互斥的,一个线程占用了某 ...

  7. python转义符的使用

    写了几行代码不能用.========有个需要的注意的就是在pycharm中看见蓝色字体要注意了一定是关键字什么,这个以后要注意. import os # g = os.walk("D:\aa ...

  8. -Dmaven.multiModuleProjectDirectory system property is not set. Check $M2_HOME environment variable and mvn script match.

    在执行[maven clean]的时候报错,错误信息如下: -Dmaven.multiModuleProjectDirectory system property is not set. Check ...

  9. AD集成库元件简写中英文对照表

    序号 英文简写 元件英文名 元件中文名 1 Res semi Semiconductor Resistor 半导体电阻 2 Cap semi Semiconductor Capacitor 半导体电容 ...

  10. 微信小程序——引用阿里云字体

    阿里图标官网:http://www.iconfont.cn 使用阿里云图标大致的方法就是:选中你的图标——保存至你的项目——下载你的图标项目——在项目中引用字体文件. 具体方法可以参考:引用阿里云矢量 ...