Рабочая нить и дипоза () - PullRequest
1 голос
/ 19 января 2010

У меня есть служебный класс с рабочим потоком с простым условием выхода. Я использую этот класс в своем приложении. Рабочий поток создан и запущен в конструкторе класса.

class MyClass
{
  Thread _thread;

// unrelevant details are omitted
void WorkerThreadRoutine
{
  while(_running)
 {
   // do some useful background work here
 }
}
}

У меня вопрос, КОГДА я должен установить _running = false. В C ++ с детерминированным жизнь освобождения ресурса легка - я использую деструкторы объекта и мне все равно.

Я бы написал что-то вроде

~MyClass()
{
  _running = false;
}

В C # нет деструкторов в смысле C ++. Должен ли я написать некоторую функцию Dispose () здесь и использовать IDisposable? Конечно, я могу предоставить функцию Stop (). Но когда я должен это назвать? Есть ли способ автоматически вызывать мою функцию Stop?

Какой здесь правильный шаблон? В моем приложении много экземпляров MyClass.

Прямо сейчас мое приложение зависает при выходе.

Ответы [ 2 ]

2 голосов
/ 19 января 2010

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

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

1 голос
/ 19 января 2010

В C ++ вы обычно явно вызываете оператор удаления. Это не отличается от явного вызова метода Stop () в C #.

Компилятор C ++ может автоматически генерировать вызов оператора delete, если ваш объект является локальной переменной метода. Это хорошо отображается на IDisposible в C # с помощью оператора using:

void SomethingSlow() {
  using (var obj = new MyClass()) {
    // etc..
  }
}

class MyClass : IDisposable {
  private ManualResetEvent mStop = new ManualResetEvent(false);
  public Dispose() {
    mStop.Set();
  }
  // etc...
}

Ваш поток, вероятно, не останавливается прямо сейчас, потому что вы забыли объявить поле _running как volatile. Использование события может помочь избежать подобных проблем. Вы можете установить для свойства потока IsBackground значение true, чтобы предотвратить зависание потока завершением вашей программы. Это пластырь, а не исправление.

...