在他的回答中,https://stackoverflow.com/a/19664437/4919475
斯蒂芬·克利里
ReaderWriterLockSlim是线程仿射锁类型,因此通常不能与异步和等待一起使用。
他所说的“通常”是什么意思?什么时候可以使用ReaderWriterLockSlim?
另外,我在这里读过http://joeduffyblog.com/2007/02/07/introducing-the-new-readerwriterlockslim-in-orcas/,ReaderWriterLockSlim有不同的怪癖,但本文是2007年的。从那以后就变了吗?
发布于 2017-05-18 00:14:57
我猜你发布了一个只有Cleary才能回答的问题,因为你想知道他的意思。
同时,从他的声明中可以明显地推断,在任何情况下,如果您能够保证获得锁的相同线程也能够释放锁,就可以在任何情况下将ReaderWriterLockSlim与async/await一起使用。
例如,您可以想象这样的代码:
private readonly ReaderWriterLockSlim _rwls = new ReaderWriterLockSlim();
async void button1_Click(object sender, EventArgs e)
{
_rwls.EnterWriteLock();
await ...;
_rwls.ExitWriteLock();
}在上面,由于Click事件将在await将返回的线程中引发,所以您可以获取锁,执行await,并且仍然可以在继续中释放锁,因为您知道它将是同一个线程。
在async/await的许多其他用法中,不能保证继续在方法产生的线程中,因此不允许它释放在await之前获得的锁。在某些情况下,这是明确有意的(即ConfigureAwait(false)),而在其他情况下,这只是await上下文的自然结果。无论哪种方式,这些场景都不像Click示例那样与Click兼容。
(我故意忽略了一个更大的问题,即获取一个锁,然后在可能长期运行的异步操作期间保持它是否是一个好主意。那就是,就像人们所说的,“一个完整的‘另一个’蜡球‘。”
增编:
对于我忽略…的“更大的问题”,“简短”的评论太长了,而不是一个实际的评论。
“更大的问题”是相当广泛和高度依赖上下文的。所以我才没说出来。简短的版本分为两部分:
持有锁的时间越长,一个或多个线程被阻塞等待的可能性就越大,它们会序列化任何工作。他们都在等待同一个锁,所以即使长时间运行的锁被释放,他们仍然必须按顺序工作,而不是同时工作。这有点像交通堵塞,一长队的汽车在等着一辆建筑卡车堵住道路,…即使卡车不挡道,也要花一些时间才能解决堵塞问题。
我不会说在异步操作期间保持锁本身就不好--也就是说,我可以想象出仔细考虑的情况--这样做是可以的--但它常常会破坏其他实现目标,而且在某些情况下,可以完全撤销本来要进行大量并发的设计,特别是在没有特别小心的情况下。
await中,您知道锁仍然存在,但是“触发和遗忘”并不少见,并且会导致代码在异步操作发生时出现锁定,但实际上并非如此(请参阅Stack溢出问题在调用/BeginInvoke期间,锁会发生什么情况?(事件调度)中的一个例子,该问题就是这样做的,甚至没有意识到这一点)。避免错误代码的一种方法就是简单地避免已知的可能导致错误的编码模式。同样,如果一个人足够小心,一个人可以避免错误。但是,通常更好的做法是简单地更改实现,以使用不太复杂的方法,并养成这样做的习惯。
发布于 2018-11-16 14:32:06
我在这个问题上注意到你问过:
你能解释一下“任意代码”是什么意思吗?
我相信,这份说明强调了“更大的问题”的一个重要方面,我将尝试-在时间紧迫的情况下-简短地谈到这个问题。这里的一个主要关注点是,等待语句不能保证它等待的Task将在与调用代码相同的上下文中运行(特别是在线程仿射锁的情况下,在同一个线程上);实际上,这将破坏Task承诺的许多目的。
假设您正在等待的Task正在等待使用Task.Run创建的Task,或者是在另一个线程上,或者已经生成当前线程等待某些后台资源(比如磁盘或网络I/O)。在这些情况下,至少有两种意想不到的行为很容易意外地被发现:
Task,该线程需要足够长的时间来处理消息泵开始处理另一条消息(例如再次单击同一按钮,或任何其他可能需要相同锁的“任意代码”),则该新消息将在拥有该锁的同一个线程上执行,因此即使上一次Task尚未完成,也允许继续执行该消息,从而允许任意访问应该同步的资源。虽然前者可能导致您的应用程序或它的某些组件被锁定,但后者可能会产生非常意外的结果,并且特别难以解决疑难解答问题。所有线程仿射锁定机制都存在类似的情况(比如Monitor,它是lock关键字的底层实现)。希望这能有所帮助。
如果您对C#中的并行模式有更多的兴趣,我可能会推荐免费的C#中的线程化电子书(这实际上是摘自其他优秀书籍"C# in a which“)。
https://stackoverflow.com/questions/44036160
复制相似问题