跳过 SemaphoreSlim 而不是等待

Posted

技术标签:

【中文标题】跳过 SemaphoreSlim 而不是等待【英文标题】:Skip SemaphoreSlim instead of wait 【发布时间】: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 的线程数”,这是模棱两可的(我解释最大)。 【参考方案1】:

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

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

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

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

【讨论】:

零超时是我所需要的!如果我的方法无法获取锁/事件/任何东西,我希望我的方法立即退出...... 换句话说:不要在锁/监视器中使用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 它有效,但非常危险 - 请参阅:***.com/a/7612714/65358 那是我的担心。我假设因为 SemaphoreSlim 有一个 Async WaitAsync 方法,所以在 WaitAsync/Release 之间放置一些等待调用是安全的,但你认为有类似的风险吗? @Charles 如果您尝试在其中等待,任何给您阻塞语义的东西都会遇到同样的问题...阅读该帖子 ;) 现在我不得不对此投反对票——这个问题是关于 async/await 的,而这对于 async/await 并不适用(正如你所指出的)

以上是关于跳过 SemaphoreSlim 而不是等待的主要内容,如果未能解决你的问题,请参考以下文章

C#ThreadSemaphore/SemaphoreSlim信号量

线程编程-使用SemaphoreSlim类

多线程-3(同步)

linux 怎么查 信号量 被进程p住

sem_wait的范例

在 Linux 中控制信号量队列中的出队顺序