实现等待条件或通过线程取消

时间:2008-10-23 17:27:31

标签: .net multithreading

我正在尝试实现以下功能:

class WeightResolver {
  WeightMonitor _source;
  bool _cancelled;
  Weight _threshold;

  public Cancel() {
      _cancelled = true;
  }
  public Weight Resolve(){
      _cancelled = false;
      while(_source.CurrentWeight < threshold ) {
         if(_cancelled)
             throw new CancelledOperationException();
         // Wait until one of the above conditions is met
      }
      return _source.CurrentWeight
  }
}

但是我遇到了管理我的线程的麻烦。例如,Cancel方法通过事件注册,Resolve调用如下:

  _activity_timeout_manager.TimeoutHandler += new Action(_weight_resolver.Cancel())l
  try {
      var weight = _weight_resolver.Resolve();
  }
  catch(CancelledOperationException) { .... }

其中活动管理器正在运行一个计时器,它使用TimeoutHandler.Invoke()调用事件;

问题在于即使它已正确注册事件,也永远不会调用Cancel()。我相信这是因为它正在调用的线程正在旋转,因此它永远不会有机会在CPU上运行。

如果不调用Resolve()异步,我该怎么做才能解决这个问题? WeightResolver.Resolve()非常适合保持同步,因为调用它的代码应该旋转,除非提供一些返回。

编辑:澄清我要求的内容。这似乎是一个相当常见的设置,如果没有一种简单的标准方法来处理它,我会感到惊讶。我以前从来没有碰过这种情况,也不知道究竟是什么。

4 个答案:

答案 0 :(得分:1)

这可能不适合您,但根据您提供的信息,我建议查看thread.Join(XXX),其中XXX是等待的毫秒数。它将大大简化您的代码。

http://msdn.microsoft.com/en-us/library/6b1kkss0.aspx

你可以将调用线程阻塞到新线程一段指定的时间,之后你可以中止Resolve线程。

resolveThread.Start();
resolveThread.Join(2000); //this will block the main thread, thus making resolve synchronous
resolveThread.Abort(); //timeout has expired

答案 1 :(得分:0)

这个while循环是否会放弃CPU?

while(_source.CurrentWeight < threshold )

如果没有,那么您的不活动计时器将无法运行。您可能希望使用ManualResetEvents(而不是循环...有任何设置_source.CurrentWeight设置事件)或每隔一段时间抛出一个Thread.yield()。

答案 2 :(得分:0)

这里需要的是条件变量。我不是专门知道.NET,但一般来说你会有类似的东西

Condition cond;
Mutex lock;

public Cancel() {
      lock.lock()
      _cancelled = true;
      cond.signal(lock);
      lock.unlock();
  }
  public Weight Resolve(){
      _cancelled = false;
      lock.lock();
      while(_source.CurrentWeight < threshold) {
         if(_cancelled)
          {
             lock.unlock();
             throw new CancelledOperationException();
           }
          cond.timedWait(lock, 100);
         // Wait until one of the above conditions is met
      }
      lock.unlock();
      return _source.CurrentWeight
  }

如果你的WeightResolver在重量变化时以相同的条件发出信号,那就更好了。 e.g。

Condition cond;
Mutex lock;

public Cancel() {
      lock.lock()
      _cancelled = true;
      cond.signal(lock);
      lock.unlock();
  }
  public Weight Resolve(){
      _cancelled = false;
      lock.lock();
      while(_source.CurrentWeight < threshold) {
         if(_cancelled)
          {
             lock.unlock();
             throw new CancelledOperationException();
           }
          cond.wait(lock);
         // Wait until one of the above conditions is met
      }
      lock.unlock();
      return _source.CurrentWeight
  }

在WeightMonitor Class中你有这样的东西。

public void updateWeight()
{
    lock.lock();
    ...update weight;
    cond.signal(lock);
    lock.unlock();
}

其中Conditionvariable和lock是相同的。两个班级。

这是条件变量的标准用法,这也是通常实现连接的方式。

答案 3 :(得分:0)

您应该使用ManualResetEvent代替bool来取消。

class WeightResolver {
  WeightMonitor _source;
  ManualResetEvent _cancelled = new ManualResetEvent(false);
  Weight _threshold;

  public Cancel() {
      _cancelled.Set();
  }
  public Weight Resolve(){
      _cancelled = false;
      while(_source.CurrentWeight < threshold ) {
         if(_cancelled.WaitOne(100))
             throw new CancelledOperationException();
         // Wait until one of the above conditions is met
      }
      return _source.CurrentWeight
  }
}