/// <summary> /// A Pausable Task cannot be recycled from the pool if hasn't been /// previously completed. /// A task can actually be restarted, but this will stop the previous /// enumeration, even if the enumerator didn't change. /// However since an enumerator can be enumerated on another runner /// a task cannot set as completed immediatly, but it must wait for /// the next MoveNext. This is what the Pending logic is about. /// </summary> /// <param name="task"></param> void InternalStart() { DBC.Check.Require(_pendingRestart == false, "a task has been reused while is pending to start"); DBC.Check.Require(_taskGenerator != null || _taskEnumerator != null, "An enumerator or enumerator provider is required to enable this function, please use SetEnumeratorProvider/SetEnumerator before to call start"); Resume(); //if it's paused, must resume var originalEnumerator = _taskEnumerator ?? _taskGenerator(); //TaskRoutine case only!! ThreadUtility.MemoryBarrier(); if (_pool == null && _completed == false && _started == true && _explicitlyStopped == true) { _pendingEnumerator = originalEnumerator; _pendingContinuationWrapper = _continuationWrapper; _pendingRestart = true; _continuationWrapper = new ContinuationWrapper(); ThreadUtility.MemoryBarrier(); return; } Restart(originalEnumerator); }
public void OnCompleted(Action continuation) { var wrapper = new ContinuationWrapper(continuation); if (_cancellationToken.IsCancellationRequested) { ThreadPool.QueueUserWorkItem(ThreadPoolCallback, wrapper); return; } _mainThread.Post(wrapper.Invoke); var registration = _cancellationToken.Register(CancellationTokenCallback, wrapper, false); var disposeRegistration = false; lock (wrapper) { // wrapper.Action == null means that ContinuationWrapper.Invoke has been called before CancellationTokenRegistration was set // In this case, registration should be disposed explicitly if (wrapper.Action == null) { disposeRegistration = true; } else { wrapper.CancellationTokenRegistration = registration; } } if (disposeRegistration) { registration.Dispose(); } }
internal PausableTask() { _coroutineWrapper = new SerialTaskCollection(1); _continuationWrapper = new ContinuationWrapper(); Reset(); }
/// <summary> /// A PausableTask cannot be recycled from the pool if hasn't been previously completed. /// A task can actually be restarted, but this will stop the previous enumeration, even if the enumerator didn't /// change. /// However since an enumerator can be enumerated on another runner a task cannot set as completed immediately, /// but it must wait for the next MoveNext. This is what the Pending logic is about. /// </summary> /// <param name="task"></param> void InternalStart() { DBC.Tasks.Check.Require(_pendingRestart == false, "a task has been reused while is pending to start"); DBC.Tasks.Check.Require(_taskGenerator != null || _taskEnumerator != null, "An enumerator or enumerator provider is required to enable this function, please use SetEnumeratorProvider/SetEnumerator before to call start"); Resume(); //if it's paused, must resume var originalEnumerator = _taskEnumerator ?? _taskGenerator(); //TaskRoutine case only!! bool isTaskRoutineIsAlreadyIn = _pool == null && _completed == false && _started == true; if (isTaskRoutineIsAlreadyIn == true && _explicitlyStopped == true) { //Stop() Start() cauess this (previous continuation wrapper will stop before to start the new one) //Start() Start() will not make the _continuationWrapper stop until the task is really completed _pendingEnumerator = originalEnumerator; _pendingContinuationWrapper = _continuationWrapper; _pendingRestart = true; _continuationWrapper = new ContinuationWrapper(); return; } Restart(originalEnumerator, isTaskRoutineIsAlreadyIn); }
public ContinuationWrapper Start(Action <SveltoTaskException> onFail = null, Action onStop = null) { DBC.Tasks.Check.Require(_taskGenerator != null || _taskEnumerator != null, "An enumerator or enumerator provider is required to enable this function, please use SetEnumeratorProvider/SetEnumerator before to call start"); _onStop = onStop; _onFail = onFail; _sveltoTask._threadSafeStates.paused = true; _sveltoTask.OnTaskInterrupted(); var continuationWrapper = _continuationWrapper; var newTask = _taskGenerator != null?_taskGenerator() : _taskEnumerator; if (_sveltoTask._threadSafeStates.isRunning == true && _sveltoTask._threadSafeStates.explicitlyStopped == true) { //Stop() Start() causes this (previous continuation wrapper will stop before to start the new one) //Start() Start() is perceived as a continuation of the previous task therefore it won't //cause the continuation wrapper to stop _pendingTask = newTask; _previousContinuationWrapper = _continuationWrapper; continuationWrapper = _continuationWrapper = new ContinuationWrapper(); Resume(); //if it's paused, must resume } else { DBC.Tasks.Check.Require(_runner != null, "SetScheduler function has never been called"); if (_taskGenerator == null && _sveltoTask._threadSafeStates.taskEnumeratorJustSet == false) { #if DEBUG && !PROFILER DBC.Tasks.Check.Assert(newTask.GetType().IsCompilerGenerated() == false, "Cannot restart a compiler generated iterator block, use SetEnumeratorProvider instead ".FastConcat(_sveltoTask._name)); #endif newTask.Reset(); } _sveltoTask.SetTask(newTask); _continuationWrapper.Reset(); _sveltoTask.ClearInvokes(); if (_sveltoTask._threadSafeStates.isRunning == false) { _sveltoTask._threadSafeStates = new SveltoTask <T> .State(); _sveltoTask._threadSafeStates.started = true; _runner.StartCoroutine(this); } else { _sveltoTask._threadSafeStates.paused = false; } } return(continuationWrapper); }
/// <summary> /// Reset task on reuse, when fetched from the Pool /// </summary> public void Reset() { CleanUpOnRecycle(); _continuationWrapper = new ContinuationWrapper(); _paused = false; _taskEnumeratorJustSet = false; _completed = false; _started = false; _explicitlyStopped = false; #if DEBUG && !PROFILER _compilerGenerated = false; #endif _pendingRestart = false; _name = string.Empty; }
/// <summary> /// Reset task on reuse, when fetched from the Pool /// </summary> public void Reset() { CleanUpOnRecycle(); //_enumeratorWrap.Reset cannot be inside //CleanUp because it could be iterated way //after the task is completed. _continuationWrapper = new ContinuationWrapper(); _paused = false; _taskEnumeratorJustSet = false; _completed = false; _started = false; _explicitlyStopped = false; _compilerGenerated = false; _pendingRestart = false; _name = string.Empty; }
internal static void Push(ContinuationWrapper task) { _pool.Enqueue(task); }
public TaskRoutine(IRunner <T> runner) { _sveltoTask = new SveltoTask <T>(); _runner = runner; _continuationWrapper = new ContinuationWrapper(); }
internal static void Push(ContinuationWrapper task) { GC.SuppressFinalize(task); //will be register again once pulled from the pool _pool.Enqueue(task); }