C#锁定和异步方法

ruf*_*ufo 22 c# multithreading

我不清楚(并且找不到足够明确的文档):在异步方法中使用lock关键字时:如果对象已经被阻塞,线程是否会被阻塞,或者它是否会在挂起状态下返回任务(不阻塞线程) ,并在释放锁时返回)?

在下面的代码中,行会阻塞线程吗?如果它阻塞线程(这是我的想法),是否有标准的阻塞解决方案?我正在考虑使用AsyncLock,但首先我想尝试标准的东西.

谢谢.

private object myLock = new object(); 

private async Task MyMethod1(){
  lock (myLock ) {// <---- will this line cause a return of the current method as an Await method call would do if myLock was already locked. 

    .... 
  }
}

// other methods that lock on myLock
Run Code Online (Sandbox Code Playgroud)

Ste*_*ary 42

在下面的代码中,行会阻塞线程吗?

从技术上讲,是的,但它不会像你期望的那样工作.

线程仿射锁不能很好地使用有两个原因async.一个是(在一般情况下),一个async方法可能无法在同一个线程上恢复,因此它会尝试释放它不拥有的锁,而另一个线程永远持有锁.另一个原因是,在一段await时间内持有锁,在锁定时可以执行任意代码.

出于这个原因,编译器不遗余力地禁止块await内的表达式lock.不过,你仍然可以通过Monitor直接使用或其他原语射击自己.

如果它阻塞线程(这是我的想法),是否有标准的阻塞解决方案?

是; 该SemaphoreSlim类型支持WaitAsync.

  • 现在谢谢我在`lock`中看到问题``await`.相反的是:在一个最终通过某种异步方法调用的方法中使用`lock`s?我的猜测是它是安全的,因为`lock`ed操作都在同一个线程上完成.但是,在这种情况下直接使用监视器似乎仍然存在问题 - 但这很糟糕,因为开发人员通常无法判断代码是否将以异步/等待方式使用.这是什么建议? (3认同)
  • 只要锁(或监视器)中只有同步代码,它就可以正常工作.它是否由异步方法调用并不重要. (2认同)
  • 我认为这就是问题所在(异步方法内的锁是否安全)。值得庆幸的是,我意识到这有点不清楚,并向下滚动到这些评论。哈哈哈。 (2认同)
  • @OfirD:有一个主要问题:“async”方法可能会在“await”之后在*不同的*线程上恢复执行,从而导致线程释放它从未获取的锁的情况。 (2认同)

use*_*220 14

这是不允许停止僵局(即开发人员伤害自己).我发现的最佳解决方案是使用semaphones - 有关详细信息,请参阅此帖子:

https://blog.cdemi.io/async-waiting-inside-c-sharp-locks/

相关代码提取:

static SemaphoreSlim semaphoreSlim = new SemaphoreSlim(1, 1);

...

await semaphoreSlim.WaitAsync();
try
{
    await Task.Delay(1000);
}
finally
{
    semaphoreSlim.Release();
}
Run Code Online (Sandbox Code Playgroud)

  • 是否有理由使信号量静态?如果信号量是一个实例变量(假设您只想锁定该类的这个实例),那么它大概也可以工作。 (2认同)
  • 就我而言,我有多个对象需要将其进度报告给数据库。我当然希望它们是异步的,所以在我的例子中静态 SemaphoreSlim 是可行的方法。 (2认同)

Sim*_*ead 5

不,不会。

lock是语法糖Monitor.EnterMonitor.Exitlock将在方法中保持执行,直到释放锁为止。它的功能不像await任何形式,形状或形式。