首页 > 解决方案 > 不执行方法释放锁

问题描述

我正在使用的系统由托管各种 WCF 服务的 Windows 服务组成。多个客户端可以与同一个服务通信,但一次只有一个客户端可以与一个服务通信。
因此,我使用“lock()”来防止多个客户端发生冲突。如果 Client1 向服务发出第一个请求,然后 Client2 在前者仍在执行时发出另一个请求,则“锁定”会暂停第二个请求,直到第一个请求完成。

到目前为止,一切都很好。现在的问题是我必须处理事件(我不认为简单的回调会在这里解决问题)。
换句话说,当第一个请求正在运行时,可能会发生一些 Client2 需要知道的事情。
发生这种情况时,Client2 将收到该事件并最终应该一起停止使用该服务。
这里的问题是我们的第二个请求已经在储物柜的队列中。
那么我将如何阻止第二个请求运行。可以取消吗?
也许这只是添加一个脏标志的问题,但我希望有更好的方法来做到这一点。
这是带有脏标志“canRun”的服务端的样子:

lock (_locker)
{ 
    if (canRun)
       return SomeMethod();
    else
       return null;
}

标签: c#wcflocking

解决方案


如果你可以切换到async/await和类似 a 的东西SemaphoreSlim,那么:CancellationToken就是你要找的东西;aCancellationTokenSource可以随时标记为已取消,并且代码可以相应地响应 - 大多数框架/库代码已经正确处理取消,例如:在异步信号量获取期间。

如果您需要坚持同步世界,那么您最好的选择可能是更改为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适当地访问或以其他方式访问,以避免被缓存在寄存器或类似物中。


推荐阅读