Собственные задачи - C#

Узнай цену своей работы

Формулировка задачи:

Привет всем! Столкнулся с тем, что в некоторых ситуациях Task.Run не сразу запускает задачу, а ставит на планирование. Первый вопрос - можно ли этого избежать? Пока ответа я не нашел, поэтому, а так же по ряду других ограничений, которые есть в оригинальной TaskModel, сделал свой пул потоков, работающий со своими задачами. Сейчас делаю await (т.е. чтобы к моим задачам тоже можно было делать await). Создал awaiter, унаследовал интерфейс ICriticalNotifyCompletion, реализовал, всё как положено. Сделал сохранение контекста синхронизации, если таковой был. Если я правильно понял, при срабатывании await у задачи вызывается GetAwaiter, который возвращает экземпляр этого самого Awaiter. У этого Awaiter вызывается метод OnCompleted, этому методу передается Continuation - делегат, оборачивающий весь код, который идет после await, и я должен его выполнить после того, как моя задача отработает. Я сохраняю этот делегат в задаче, и она, после выполнения, запускает этот Continuation. При тестировании выяснилось, что код после await срабатывает не всегда. Происходит это, как я выяснил, потому, что OnCompleted у аваитера в некоторые моменты вызывается уже после того, как задача выполнилась, соответственно, Continuation делать она уже не будет. Понятное дело - это же параллельные потоки. Теперь вопрос - как сделать так, чтобы OnCompleted вызывалось до старта задачи? Как узнать, что вот эта задача должна сначала дождаться вызова метода OnCompleted с передачей делегата? Или как вообще определить, что задача, хоти выполнила свой основной код до конца, должна дождаться еще и continuation-кода? Или как вообще это делают? Понимаю, что дич сложная, рассчитываю на то, что может кто-то тоже писал TaskModel, и как-то решил данную проблему. Заранее спасибо. PS. Да, я знаю про рефлектор, сейчас пока безуспешно пытаюсь понять как это делает оригинальная TaskModel.

Решение задачи: «Собственные задачи»

textual
Листинг программы
class MyAwaiter : INotifyCompletion
{
   private Action continuation;
 
   public bool IsCompleted { get; private set; }
   public object GetResult() => null;
   public void OnCompleted(Action continuation)
   {
      if (IsCompleted)
         continuation(); // Метод вызвался уже после окончания задачи, так что просто вызываем делегат
      else
         this.continuation = continuation; // Сохраняем на потом
   }
   public MyAwaiter GetAwaiter()
   {
      new Thread(RunParallelOperation).Start();
      return this;
   }
 
   private void RunParallelOperation()
   {
      // Чего-нибудь делаем...
 
      IsCompleted = true;
      
      // Делегат уже передали?
      if (continuation != null)
         continuation();
   }
}

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

14   голосов , оценка 4.214 из 5