不执行方法释放锁
Posted
技术标签:
【中文标题】不执行方法释放锁【英文标题】:Releasing lock without executing a method 【发布时间】:2021-07-05 04:38:10 【问题描述】:我正在使用的系统由一个托管各种 WCF 服务的 Windows 服务组成。多个客户端可以与同一个服务通信,但一次只有一个客户端可以与一个服务通信。 因此,我使用“lock()”来防止多个客户端发生冲突。如果 Client1 向服务发出第一个请求,然后 Client2 在前者仍在执行时发出另一个请求,则“锁定”会暂停第二个请求,直到第一个请求完成。
到目前为止一切顺利。现在的问题是我必须处理事件(我不认为简单的回调在这里可以解决问题)。 换句话说,当第一个请求正在运行时,可能会发生一些 Client2 需要知道的事情。 发生这种情况时,Client2 将收到该事件,并最终应该一起停止使用该服务。 这里的问题是我们的第二个请求已经在储物柜的队列中。 那么我将如何阻止第二个请求运行。可以取消吗? 也许这只是添加一个脏标志的问题,但我希望有更好的方法来做到这一点。 这是带有脏标志“canRun”的服务端的样子:
lock (_locker)
if (canRun)
return SomeMethod();
else
return null;
【问题讨论】:
取消进程的首选方法是使用CancellationToken
。但是,您应该扩展您的示例以使您的用例更加清晰。我看不出事件是如何在这里发挥作用的。
感谢@PMF,这是因为客户实际上需要知道发生了什么,但我认为它不会负责根据该事件取消请求(可能不可能)?或者这就是 CancellationToken 的意义所在?
谁可以触发取消取决于您的实施。如前所述,您需要提供更多上下文。
我想你也可以将服务设置为单线程:docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/…
感谢@Ding Peng,但我确实需要将 ConcurrencyMode 设置为 Multiple
【参考方案1】:
如果您可以切换到async
/await
和类似SemaphoreSlim
,那么:CancellationToken
就是您要找的; CancellationTokenSource
可以随时标记为已取消,并且代码可以相应地响应 - 大多数框架/库代码已经正确处理取消,例如:在异步信号量获取期间。
如果您需要坚持同步世界,那么您最好的选择可能是更改为循环的Monitor
模式,该模式可以重新检查每次超时,例如:
bool lockTaken = false;
try
do
if (!canRun) throw new OperationCanceledException();
Monitor.TryEnter(_locker, someTimeout, ref lockTaken);
while (!lockTaken);
// now we have the conch
SomeMethod();
finally
if (lockTaken) Monitor.Exit(_locker);
请注意,如果 canRun
是一个字段,您需要确保它是 volatile
或以其他方式适当访问以避免缓存在寄存器或类似物中。
【讨论】:
lockTaken
在您的示例中永远不会更新。此外,这会导致忙等待。
@PMF 哎呀,我错过了ref
!固定的;这不是一个热循环;它比问题中的代码更忙,是的,但它也不会挂在 CPU 上
感谢您的回答。这是常见的做法吗?如果我在每个 API 的方法中添加该代码,它会变得很忙。
@stackMeUp 我会说 scenario 并不是那么常见,至少在 lock
中是这样;我同意,这很混乱; CancellationToken
会方便得多,但这不适用于lock
/Monitor
好的,我将探索 CancellationToken 选项,看看是否可以使用它:-)以上是关于不执行方法释放锁的主要内容,如果未能解决你的问题,请参考以下文章