c# - 在异步或同步操作中使用监视器锁

标签 c# .net async-await c#-7.0

<分区>

我正在尝试提供一种锁定全局资源的解决方案,该方式要求锁定访问权限并且可用于同步或异步操作。

我创建了一个通用类 State:

public class State<T>
{
  public class LockedState : IDisposable {
    public LockedState(State<T> state) { this.state = state; Monitor.Enter(this.state.theLock); } // would be great if this could be private
    public void Dispose() => Monitor.Exit(this.state.theLock);
    public ref T Val { get { return ref state.t; } }

    readonly State<T> state;
  };

  public State() { }
  public State(T t) { this.t = t; }
  public LockedState Locked { get { return new LockedState(this); } }
  readonly object theLock = new object();
  T t;
}

这里的想法是我可以在 Program 类中拥有一个全局“商店”:

public class Program {
    static public readonly State<ImmutableList<int>> TheList = new State<ImmutableList<int>>(ImmutableList<int>.Empty);
    static public readonly State<SomeType> SomeType = new State<SomeType>(SomeType());
}

然后访问状态的唯一方法是像这样获取锁:

using (var lTheList = Program.TheList.Locked) {
   lTheList.Val = lTheList.Val.Add(5));
}

在我的例子中,它比普通锁工作得更好,因为它在获取/设置之前强制锁定(你不能忘记锁定)

(旁注这是一个好策略吗?)

问题是我不能在异步代码中使用上面的内容:

using (var someType = Program.SomeType.Lock()) {
   var x = await someType.Val.SomeAsyncOp();
}

我得到一个异常:从未同步的代码块调用了对象同步方法

我找到了这篇文章 How to protect resources that may be used in a multi-threaded or async environment?它有一个 AsyncLock 类但是我不明白如何将 AsyncLock 这样的类放入我的 StateLock 类中..

State.Lock() 能否返回可用于同步和异步调用方的锁定状态?这正是我要找的!

如果不是,我最好的前进方向是什么?使用 SemaphoreSlim 并使用 State.Lock()State.AsyncLock()

谢谢!

最佳答案

您不能在此处使用 Monitor,因为 Monitor(又名 lock)本质上是基于线程的,需要您“退出”来自 获取 锁的同一个线程的锁 - 这正是您在 async 代码中很少想到的情况。相反,请考虑 SemaphoreSlim,您可以从中获取和释放 token ,但不是线程绑定(bind)的。

伪代码:

// usually a field somewhere
SemaphoreSlim obj = new SemaphoreSlim(1);

// acquire lock:
obj.Wait(); // or await obj.WaitAsync() if want async acquire

// release lock:
obj.Release(); // often in a "finally"

关于c# - 在异步或同步操作中使用监视器锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53864799/

相关文章:

c# - HANA服务层: Could not establish trust relationship for the SSL/TLS secure channel

c# - 使用 SocketAsyncEventArgs 的服务器设计

c# - 分解集中式数据库的最具成本效益的方法是什么?

c# - 将 System.Data.OracleClient 替换为 Oracle.DataAccess (ODP.NET)

c# - 具有 CancellationTokenSource 的 channel 在处理后出现超时内存泄漏

python - 在单独的线程中执行 run_coroutine_threadsafe

c# - 进程完成时从 azure 函数发送电子邮件

c# - 如何在 C# 中对 ALEA 库使用递归

C#6.0 字符串插值本地化

c# - 在 ContinueWith() 之后,ConfigureAwait(False) 不会改变上下文