不执行方法释放锁

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 选项,看看是否可以使用它:-)

以上是关于不执行方法释放锁的主要内容,如果未能解决你的问题,请参考以下文章

不执行方法释放锁

java锁-分类

PThread 强大的互斥锁不起作用

如果对象在其方法执行完成之前被释放怎么办

线程

java线程的一些方法和特性