【问题标题】:Skip SemaphoreSlim instead of wait跳过 SemaphoreSlim 而不是等待
【发布时间】:2014-10-07 10:48:03
【问题描述】:

我在 Async/Await 函数中有一部分代码,我希望一次只执行一个线程。

通过创建一个新的 SemaphoreSlim(1) 并使用 WaitAsync/Release,这相对简单。效果是第一个线程执行,其他线程等待,然后一个接一个地执行。

我想要达到的效果实际上略有不同。我希望其他线程不要等待,而是从函数中返回(即我不想阻塞其他线程)。因此,如果有一个属性“NumberOfThreadsCurrentlyExecuting”,我实际上会有一个 If Semaphore.NumberOfThreadsCurrentlyExecuting > 0 Then Return。

但是这样的属性不存在。有没有人知道解决这个问题的方法?

谢谢 查尔斯

【问题讨论】:

  • 检查CurrentCount?
  • 对。愚蠢的问题。对不起!我知道 CurrentCount 指的是最大线程数而不是剩余线程数。
  • 并意识到我的错误来自哪里:VS 中 CurrentCount 的工具提示说“获取允许进入 System.Threading.SemaphoreSlim 的线程数”,这是模棱两可的(我解释最大)。

标签: c# vb.net multithreading


【解决方案1】:

Charles,使用具有零超时的SemaphoreSlim.Wait/Async 怎么样?如果不能输入信号量(因为已经输入),则返回false。

请注意Monitor(因此lock)完全不适合async

(因此你不能在lock 中使用await)因为

  1. 进入锁后,您的任务可能会在另一个线程上继续(因此您将尝试从另一个线程释放锁)
  2. 在您等待之后,另一个延续可能会使用您的线程(当它仍然持有锁时),因此如果它尝试获取锁,它将成功

【讨论】:

  • 零超时是我所需要的!如果我的方法无法获取锁/事件/任何东西,我希望我的方法立即退出......
  • 换句话说:不要在锁/监视器中使用await。感谢Wait(0) 提示!
【解决方案2】:

您可以只使用Monitor,而不是信号量。

如果调用TryEnter 失败,则另一个线程处于“锁定”状态。

这是线程安全的(不同于检查信号量计数),并且相当简单:

// 使用类似:object sync = new object();

bool lockTaken = Monitor.TryEnter(sync);
try
{
  if (lockTaken) 
  {
      // You're here - do your work
  }
  else
  {
      // Something else was in the thread - exit?
      return;
  }
}
finally
{
   if (lockTaken) Monitor.Exit(sync);
}

【讨论】:

  • 谢谢。这也是个好办法!它适用于异步/等待吗? Await 在 SyncLock 中是不允许的,我原以为这看起来很接近锁。
  • @Charles 它有效,但非常危险 - 请参阅:stackoverflow.com/a/7612714/65358
  • 那是我的担心。我假设因为 SemaphoreSlim 有一个 Async WaitAsync 方法,所以在 WaitAsync/Release 之间放置一些等待调用是安全的,但你认为有类似的风险吗?
  • @Charles 如果您尝试在其中等待,任何给您阻塞语义的东西都会遇到同样的问题...阅读该帖子 ;)
  • 现在我不得不对此投反对票——这个问题是关于 async/await 的,而这对于 async/await 并不适用(正如你所指出的)
猜你喜欢
  • 1970-01-01
  • 2023-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-04
  • 2017-06-28
  • 1970-01-01
相关资源
最近更新 更多