【问题标题】:Dispose a SemaphoreSlim while WaitAsync在 WaitAsync 时释放 SemaphoreSlim
【发布时间】:2015-11-09 05:37:32
【问题描述】:

SemaphoreSlim 的文档说“只有在所有其他操作都完成后才能使用 Dispose”。

应如何调整以下类,以便线程 B 可以在线程 A 等待 Async() 时调用 Dispose()。调用 Dispose() 时,Async() 必须抛出 ObjectDisposedException。

class A
{
   SemaphoreSlim _sem = new SemaphoreSlim(0);
   public Task Async() { return _sem.WaitAsync(); }
   public void Dispose() { _sem.Dispose(); }
}

【问题讨论】:

  • 在这种情况下,为什么要让线程 B 调用 Dispose()
  • Dispose 被称为取消所有未决请求并释放资源的一种手段。
  • 但是Dispose() 没有理由取消任何东西。如果要取消,请取消传递给WaitAsyncCancellationToken 和同一批次请求中的任何其他异步方法。

标签: .net multithreading semaphore dispose idisposable


【解决方案1】:

应该如何调整下面的类,以便线程 B 可以在线程 A 等待 Async() 时调用 Dispose()

不应该。正如您引用的文档所述,如果未完成所有操作,则不应调用 Dispose()。如果有线程仍在等待WaitAsync(),则该操作未完成,因此不应调用Dispose()

来自评论:

Dispose 被称为取消所有挂起的请求并释放资源的方法。

这是一种不明智的取消请求的方式。

当然,如果您执行的操作将对象置于无效状态,它可能会在其他线程中导致异常可能导致它们中止并因此放弃它们的工作。

但不能保证他们应该这样做,而且他们也很有可能会被编码,以免在此时出现此类异常并进行适当的清理。

如果要取消,请进行正常取消。这样创建任务:

public Task Async(CancellationToken cancellationToken)
{
  return _sem.WaitAsync(cancellationToken);
}

并使用cancellationToken 取消。

【讨论】:

  • Jon Hanna,HttpClient.Dispose 是取消挂起请求并释放资源的方法的一个示例。它在内部使用了cancellationToken。你能给出一个代码示例,它处理信号量并使用cancellationToken,同时保持A类的接口吗?
  • "HttpClient.Dispose 是取消挂起请求并释放资源的方法的示例" 不完全;它释放资源,这样做意味着取消挂起的请求,因为它是一个 HTTP 客户端。 “你能给出一个代码示例,它处理信号量并使用cancellationToken,同时保留类A的接口吗?”不,该接口未定义为允许取消。如果它既不接受方法调用中的令牌,也没有办法为所有调用的方法设置令牌,则不定义为支持取消...
  • ... 但是,如果您可以添加到接口但不能删除,那么您可以添加属性或构造函数参数来设置要由该类的所有方法使用的标记,可能默认为 @ 987654326@.
  • 但是 CancellationToken 也不能解决问题。即使您调用 {_cancellationTokenSource.Cancel(); _sem.Dispose();仍然在黑洞中留下一些 _sem.WaitAsync(cancellationToken) 直到进程存在!处置 A 类的最佳方法是什么?
猜你喜欢
  • 2021-12-22
  • 2021-11-16
  • 2012-04-25
  • 2011-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-02-02
  • 1970-01-01
相关资源
最近更新 更多