Реализация ожидания для условия или отмена с потоками - PullRequest
1 голос
/ 23 октября 2008

Я пытаюсь реализовать следующие функции:

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 () никогда не вызывается. Я полагаю, что это потому, что поток, к которому он обращается, в данный момент вращается, и поэтому у него никогда не будет шанса на процессоре.

Что я могу сделать, чтобы исправить ситуацию, не делая асинхронный вызов Resolve ()? Для WeightResolver.Resolve () крайне предпочтительно оставаться синхронным, потому что вызывающий его код должен вращаться, если в любом случае не будет предоставлен какой-либо возврат.

РЕДАКТИРОВАТЬ: Чтобы уточнить, что я прошу. Это похоже на довольно распространенную установку, и я был бы удивлен, если бы не было простого стандартного способа справиться с этим. Я просто никогда не сталкивался с ситуацией раньше и не знаю, что именно это может быть.

Ответы [ 4 ]

1 голос
/ 23 октября 2008

Это может не сработать, но исходя из предоставленной вами информации, я бы посоветовал посмотреть на thread.Join (XXX), где XXX - это количество миллисекунд ожидания. Это значительно упростит ваш код.

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

вы можете заблокировать вызывающий поток для нового потока на указанное время, после чего вы можете прервать поток разрешения.

resolveThread.Start();
resolveThread.Join(2000); //this will block the main thread, thus making resolve synchronous
resolveThread.Abort(); //timeout has expired
0 голосов
/ 23 октября 2008

Вы должны использовать 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
  }
}
0 голосов
/ 23 октября 2008

Здесь вам нужны переменные условия. Я не знаю конкретно для .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 сигнализировал о том же состоянии, когда вес изменился. например,

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 у вас было что-то вроде этого.

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

, где Условные переменные и блокировки совпадают. в обоих классах.

Это довольно стандартное использование для условных переменных, так же, как правило, реализуется объединение.

0 голосов
/ 23 октября 2008

Является ли этот цикл while отказом от процессора?

while(_source.CurrentWeight < threshold )

Если нет, то ваш таймер неактивности не сможет работать. Возможно, вы захотите использовать ManualResetEvents (вместо цикла ... есть все, что устанавливает _source.CurrentWeight, чтобы установить событие) или добавлять Thread.yield () время от времени.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...