【问题标题】:How to wait for a boolean without looping (using any kind of wait / semaphore / event / mutex, etc)如何在不循环的情况下等待布尔值(使用任何类型的等待/信号量/事件/互斥锁等)
【发布时间】:2012-09-06 21:21:00
【问题描述】:

我需要停止一个线程,直到另一个线程设置一个布尔值并且我不想在它们之间共享一个事件

我目前拥有的是以下使用睡眠的代码(这就是我要更改的代码):

while (!_engine.IsReadyToStop())
{
    System.Threading.Thread.Sleep(Properties.Settings.Default.IntervalForCheckingEngine); 
}

有什么想法吗?

编辑以澄清事情:

我不拥有一个名为 _engine 的类的对象。我无法修改它,这就是为什么我不想在它们之间共享事件。我需要等到该类的方法返回 true。

【问题讨论】:

  • 您为什么不想分享活动?有两种方法可以做你想做的事:事件或旋转。
  • 您想共享一个布尔值而不是一个事件。为什么?有什么区别?
  • 好的,你得到了答案。不,你不能
  • 好吧,如果您无法更改该类并且它与终止通信的唯一方式是使用该布尔值,那么恐怕您除了旋转之外什么也做不了。
  • 如果 'engine' 的东西调用了 'OnReadyToStop' 事件,而不是提供这种愚蠢的轮询方法,那会更友好,但你似乎被它困住了。真的需要引擎重建..

标签: c# .net multithreading mutex semaphore


【解决方案1】:

SpinWait.SpinUntil 是正确的答案,无论您要将这段代码放在哪里。 SpinUntil 提供"a nice mix of spinning, yielding, and sleeping in between invocations"

【讨论】:

  • 不如锁,但似乎是目前唯一可行的方法,而且比手动等待要好得多。
【解决方案2】:

如果你使用C# 4.0,你可以使用:

Task t = Task.Factory.StartNew (() => SomeCall(..));
t.Wait();

通过使用Task.Wait 方法。

如果你有多个任务一个接一个地运行,你可以使用Task.ContinueWith

 Task t = Task.Factory.StartNew (() =>SomeCall(..)).
                                ContinueWith(ExecuteAfterThisTaskFinishes(...);
 t.Wait();

【讨论】:

  • 生成一个任务并立即加入它有什么意义?而且我认为这不是 OP 的问题。
  • @Tudor:我对此也有疑问,所以添加关于ContinueWith的解释
  • 我希望现在问题更清楚了。如果不是第一枪,我的错。
  • 由于问题不是等待任务结束,而是等待设置值,我认为建议的解决方案不适用。有意义吗?
  • @SoMoS:由于您的请求等待布尔更改,因此 L.B 的回答更有意义。就在您从线程设置布尔值Set 事件的那一刻。
【解决方案3】:

声明为

 AutoResetEvent _ReadyToStop = new AutoResetEvent(false);

并用作

 _ReadyToStop.WaitOne();

 _ReadyToStop.Set();

欲了解更多信息,请参阅Synchronization Primitives in .Net

【讨论】:

  • Ready to stop 是一种返回布尔值的方法,并且该方法在多个地方使用,这就是为什么我说我不想在它们之间共享事件,据我所知您的回答无效。
  • @SoMoS 好笑,那就换个名字
  • ReadyToStop 只是他给 AutoResetEvent 变量起的名字。
  • 我希望现在问题更清楚了。如果不是第一枪,我的错。
【解决方案4】:

条件变量是可用于等待条件的同步原语。

它本身并不存在于 .NET 中。但是下面的link 为根据 SemaphoreSlim、AutoResetEvent 和 Monitor 类实现的条件变量类提供了 100% 的托管代码。它允许线程等待一个条件。并且可以在满足条件时唤醒一个或多个线程。此外,它还支持超时和 CancellationTokens。

要等待一个条件,您编写类似于以下的代码:

object queueLock = new object();

ConditionVariable notEmptyCondition = new ConditionVariable();

T Take() {

  lock(queueLock) {

    while(queue.Count == 0) {

      // wait for queue to be not empty
      notEmptyCondition.Wait(queueLock);
    }

    T item = queue.Dequeue();

    if(queue.Count < 100) {

      // notify producer queue not full anymore
      notFullCondition.Pulse();
    }

    return item;
  }
}

然后在另一个线程中你可以唤醒一个或多个等待条件的线程。

lock(queueLock) {

  //..add item here

  notEmptyCondition.Pulse(); // or PulseAll
}

【讨论】:

  • .NET 有监视器不需要单独的条件变量,除非您需要使用同一个锁共享多个条件变量,但我怀疑这是 OP 需要的。
猜你喜欢
  • 1970-01-01
  • 2010-12-07
  • 1970-01-01
  • 1970-01-01
  • 2015-07-12
  • 1970-01-01
  • 1970-01-01
  • 2011-08-06
  • 1970-01-01
相关资源
最近更新 更多