Собственные задачи - 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(); } }
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д