ac# web 服务中超时的锁

发布于 2024-11-19 18:52:39 字数 206 浏览 5 评论 0原文

我的网络服务有这个代码

lock(typeof MyWebServiceClass)

,我称之为第三方不可更改的代码,它永远不会返回。繁荣!嘭!

我现在被永远锁定了,我的网站崩溃了。

这种情况一去不复返,只是偶尔发生一次。

是否可以创建一个超时锁? IE锁定代码5分钟然后释放锁定?

My web service has this code

lock(typeof MyWebServiceClass)

Well i call a 3rd party unchangeable code and it never returns. BOOM! BAM!

I am locked forever now and my web site crashes.

This never returns only happens once in a great while.

Is it possible to create a lock that times out? IE lock the code for 5 minutes then release the lock?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

甜味拾荒者 2024-11-26 18:52:40

如果第 3 方 API 有取消机制,则使用该机制。

lock(typeof MyWebServiceClass)
{
  if (ThirdPartyApiThatAcceptsTimeout(TimeSpan.FromMinutes(5)))
  {
    // The call was successful so proceed.
  }
  else
  {
    // The call timed out so bail out.
    return;
  }
}

但是,我高度怀疑这个 API 没有取消机制,所以这就是你提出这个问题的原因。如果是这样的话,那么事情就会变得更加困难。

最简单的方法是将 API 调用推迟到另一个线程。如果线程没有及时响应,那么您可以中止它。

lock(typeof MyWebServiceClass)
{
  var thread = new Thread(
    () =>
    {
      ThirdPartyApiThatCouldBlockIndefinitely();
    });
  thread.Start();
  if (thread.Join(TimeSpan.FromMinutes(5))
  {
    // The call was successful so proceed.
  }
  else
  {
    // The call timed out so bail out.
    thread.Abort();
    return;
  }
}

但这也存在很多问题。首先,不能保证线程会接受中止请求。从 2.0 开始,CLR 中有一些特殊的规则来规定何时可以将中止注入到线程中。我相信 CLR 会在非托管代码执行时推迟注入。因此,如果您的 API 不受管理,那么中止可能不起作用。此外,中止是自愿的,因为线程可以捕获 ThreadAbortException 并忽略它。其次,中止是危险的,因为中止可以异步注入。这使得防止破坏共享状态变得非常困难。这就是 AppDomain 通常在中止后终止的原因。

处理此问题最安全的方法是将 API 调用放入单独的进程中。您必须使用进程间通信协议(例如 .NET Remoting、WCF、管道等)来将数据传输到调用或从调用中传输数据,这维护起来非常痛苦。但是,这将是最安全的,因为您可以安全地终止进程,而不会有损坏调用者的 AppDomain 的风险。

我真的很同情你,因为这个问题真的很难正确解决。

If the 3rd party API has a cancellation mechanism then use that.

lock(typeof MyWebServiceClass)
{
  if (ThirdPartyApiThatAcceptsTimeout(TimeSpan.FromMinutes(5)))
  {
    // The call was successful so proceed.
  }
  else
  {
    // The call timed out so bail out.
    return;
  }
}

However, I highly suspect that this API does not have a cancellation mechanism and so that is why you posed this question. If that is the case then this just got exponentially harder.

The naive approach would be to defer the API call to another thread. If the thread does not respond in a timely fashion then you can abort it.

lock(typeof MyWebServiceClass)
{
  var thread = new Thread(
    () =>
    {
      ThirdPartyApiThatCouldBlockIndefinitely();
    });
  thread.Start();
  if (thread.Join(TimeSpan.FromMinutes(5))
  {
    // The call was successful so proceed.
  }
  else
  {
    // The call timed out so bail out.
    thread.Abort();
    return;
  }
}

There are many problems with this though. First, there is no guarantee that the thread will accept the abort request. Since 2.0 there are special rules in the CLR that dictate when aborts can be injected into the thread. I believe the CLR will defer the injection while unmanaged code is executing. So if your API is unmanaged then the abort might not work. Also, aborts are voluntary since the thread could catch ThreadAbortException and ignore it. Second, aborting is dangerous since the abort can be injected asynchronously. This makes it very difficult to guard against corrupting shared state. That is why the AppDomain is normally terminated after an abort.

The safest way to handle this is to put the API call into a separate process. You would have to use interprocess communication protocols like .NET Remoting, WCF, pipes, etc. to transfer data to/from the call which would be a real pain to maintain. But, it would be the safest since you can safely kill the process without the risk of corrupting the AppDomain of the caller.

I really feel for you because this problem is really hard to solve correctly.

注定孤独终老 2024-11-26 18:52:39

我不会创建定时锁,而是通过将其放入单独的线程/任务中来限制您的第三方请求。然后,启动线程(或任务,如果您可以使用 .NET 4.0 和 TPL)并加入超时响应。如果连接超时,则取消线程(或调用 TPL 任务上的取消标记)。

Instead of creating a timed lock, I would limit your third party request by putting it in a separate thread/task. Then, kick off the thread (or task if .NET 4.0 and TPL available to you) and join on the response with a timeout. If the join times out, then cancel the thread (or call the cancel token on the TPL task).

无人问我粥可暖 2024-11-26 18:52:39

是否可以创建超时锁?

是的,这种令人不快的情况通常被称为死锁

通常,最好锁定静态私有对象,而不是锁定实例字段或类本身:

private static object _syncRoot = new object();

然后:

lock(_syncRoot) {

}

Is it possible to create a lock that times out?

Yes, this unpleasant situation is often refereed to as deadlock.

Usually it is good practice to lock on a static private object instead of locking on instance fields or the class itself:

private static object _syncRoot = new object();

and then:

lock(_syncRoot) {

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文