Книга: Программирование мобильных устройств на платформе .NET Compact Framework

Листинг 9.1. Код для управления выполнением одиночной задачи фоновым потоком

Листинг 9.1. Код для управления выполнением одиночной задачи фоновым потоком

using System; 

public class ThreadExecuteTask {
 //Перечисляем возможные состояния
 public enum ProcessingState {
  //-------------------
  //Начальное состояние
  //-------------------
  //Пока ничего интересного не происходит
  notYetStarted,
  //-----------------
  //Рабочие состояния
  //-----------------
  //Ожидание запуска фонового потока
  waitingToStartAsync,
  //Выполнение кода в фоновом потоке
  running,
  //Запросить отмену выполнения вычислений
  requestAbort,
  //--------------------
  //Состояния завершения
  //--------------------
  //Состояние завершения: выполнение фонового потока
  //успешно завершено
  done,
  //Состояние завершения: выполнение потока отменено
  //до его завершения
  aborted
 }
 ProcessingState m_processingState;
 public delegate void ExecuteMeOnAnotherThread(ThreadExecuteTask checkForAborts);
 private ExecuteMeOnAnotherThread m_CallFunction;
 private object m_useForStateMachineLock;
 public ThreadExecuteTask(ExecuteMeOnAnotherThread functionToCall) {
  //Создать объект, который мы можем использовать
  //в конечном автомате в целях блокировки
  m_useForStateMachineLock = new Object();
  //Обозначить готовность к началу выполнения
  m_processingState = ProcessingState.notYetStarted;
  //Сохранить функцию, которую необходимо вызвать
  //в новом потоке
  m_CallFunction = functionToCall;
  //----------------------------------------------------------
  //Создать новый поток и вызвать в нем функцию на выполнение:
  // this.ThreadStartPoint()
  //----------------------------------------------------------
  System.Threading.ThreadStart threadStart;
  threadStart = new System.Threading.ThreadStart(ThreadStartPoint);
  System.Threading.Thread newThread;
  newThread = new System.Threading.Thread(threadStart);
  //Обозначить готовность к началу выполнения (в целях определенности
  //это важно сделать еще до того, как будет запущен поток!)
  setProcessingState(ProcessingState.waitingToStartAsync);
  //Дать ОС команду начать выполнение нового потока в асинхронном режиме
  newThread.Start();
  //Возвратить управление функции, вызывающей этот поток
 }
 //---------------------------------------------
 //Эта функция является точкой входа, вызываемой
 //для выполнения в новом потоке
 //---------------------------------------------
 private void ThreadStartPoint() {
  //Установить состояние обработки, соответствующее
  //выполнению функции в новом потоке!
  setProcessingState(ProcessingState.running);
  //Запустить на выполнение пользовательский код и передать указатель в
  //наш класс, чтобы этот код мог периодически проверять, не поступил ли
  //запрос на прекращение выполнения
  m_CallFunction(this);
  //Если выполнение не было отменено, изменить состояние таким образом,
  //чтобы оно соответствовало успешному завершению
  if (m_processingState != ProcessingState.aborted) {
   //Обозначить завершение выполнения
   setProcessingState(ProcessingState.done);
  }
  //Выйти из потока...
 }
 //----------------
 //Конечный автомат
 //----------------
 public void setProcessingState(ProcessingState nextState) {
  //B любой момент времени только одному потоку выполнения
  //могут быть разрешены попытки изменить состояние
  lock(m_useForStateMachineLock) {
   //B случае попытки повторного вхождения в текущее состояние
   //никакие дополнительные действия не выполняются
   if (m_processingState == nextState) {
    return;
   }
   //------------------------------------------------------
   //Простейший защитный код, гарантирующий
   //невозможность перехода в другое состояние, если задача
   //либо успешно завершена, либо успешно отменена
   //------------------------------------------------------
   if ((m_processingState == ProcessingState.aborted) ||
       (m_processingState == ProcessingState.done)) {
    return;
   }
   //Убедиться в допустимости данного изменения состояния
   switch (nextState) {
   case ProcessingState.notYetStarted:
    throw new Exception("Переход в состояние 'notYetStarted' невозможен");
   case ProcessingState.waitingToStartAsync:
    if (m_processingState != ProcessingState.notYetStarted) {
     throw new Exception("Недопустимое изменение состояния");
    }
    break;
   case ProcessingState.running:
    if (m_processingState != ProcessingState.waitingToStartAsync) {
     throw new Exception("Недопустимое изменение состояния");
    }
    break;
   case ProcessingState.done:
    //Мы можем завершить работу лишь тогда, когда она выполняется.
    //Это возможно также в тех случаях, когда пользователь затребовал
    //отмену выполнения, но работа к этому моменту уже была закончена
    if ((m_processingState != ProcessingState.running) &&
       (m_processingState != ProcessingState.requestAbort)) {
     throw new Exception("Недопустимое изменение состояния");
    }
    break;
   case ProcessingState.aborted:
    if (m_processingState != ProcessingState.requestAbort) {
     throw new Exception("Недопустимое изменение состояния");
    }
    break;
   }
   //Разрешить изменение состояния
   m_processingState = nextState;
  }
 }
 public ProcessingState State {
  get {
   ProcessingState currentState;
   //Предотвратить попытки одновременного чтения/записи состояния
   lock(m_useForStateMachineLock) {
    currentState = m_processingState;
   }
   return currentState;
  }
 }
} //Конец класса

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

Оглавление книги


Генерация: 1.236. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз