Выбрать главу

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:

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

    //Это возможно также в тех случаях, когда пользователь затребовал

    //отмену выполнения, но работа к этому моменту уже была закончена