/// <summary> /// Creates a new task and starts executing it. /// </summary> /// <returns> /// The new executing task. /// </returns> /// <param name='taskFactory'> /// Task factory to start with. /// </param> /// <param name='coroutine'> /// The coroutine to start. /// </param> /// <param name='cancellationToken'> /// Cancellation token. /// </param> /// <param name='creationOptions'> /// Creation options. /// </param> /// <param name='scheduler'> /// Scheduler. /// </param> public static Task StartNew(this TaskFactory taskFactory, IEnumerator coroutine, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler) { var task = new YieldableTask(coroutine, cancellationToken, creationOptions); task.Start(scheduler); return(task); }
/// <summary> /// Creates a new task and starts executing it. /// </summary> /// <returns> /// The new executing task. /// </returns> /// <param name='taskFactory'> /// Task factory to start with. /// </param> /// <param name='instruction'> /// The instruction to start. /// </param> /// <param name='cancellationToken'> /// Cancellation token. /// </param> /// <param name='creationOptions'> /// Creation options. /// </param> /// <param name='scheduler'> /// Scheduler. /// </param> public static Task StartNew(this TaskFactory taskFactory, FiberInstruction instruction, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler) { var task = new YieldableTask(instruction, cancellationToken, creationOptions); task.Start(scheduler); return(task); }
/// <summary> /// Continues the task with a coroutine. /// </summary> /// <returns> /// The continued task. /// </returns> /// <param name='task'> /// Task to continue. /// </param> /// <param name='instruction'> /// The instruction to continue with. /// </param> /// <param name='cancellationToken'> /// Cancellation token. /// </param> /// <param name='continuationOptions'> /// Continuation options. /// </param> /// <param name='scheduler'> /// Scheduler to use when scheduling the task. /// </param> public static Task ContinueWith(this Task task, FiberInstruction instruction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { if (instruction == null) { throw new ArgumentNullException("instruction"); } if (scheduler == null) { throw new ArgumentNullException("scheduler"); } if (!(scheduler is FiberTaskScheduler)) { throw new ArgumentException("The scheduler for a YieldableTask must be a FiberTaskScheduler", "scheduler"); } // This creates a continuation that runs on the default scheduler (e.g. ThreadPool) // where it's OK to wait on a child task to complete. The child task is scheduled // on the given scheduler and attached to the parent. //var outerScheduler = TaskScheduler.Current; //if(outerScheduler is MonoBehaviourTaskScheduler) // outerScheduler = TaskScheduler.Default; var outerScheduler = TaskScheduler.Default; // The thread pool scheduler cannot be used in web scenarios. The outer scheduler // must be the fiber scheduler. //var outerScheduler = scheduler; return(task.ContinueWith((Task antecedent) => { var yieldableTask = new YieldableTask(instruction, cancellationToken, TaskCreationOptions.AttachedToParent); yieldableTask.Start(scheduler); }, cancellationToken, continuationOptions, outerScheduler)); }
/// <summary> /// Execute the specified coroutine associated with a yieldable task. /// </summary> /// <remarks> /// Any exceptions that occur while executing the fiber will be /// associated with the specified task and rethrown by the framework. /// </remarks> /// <param name="task"> /// The task associated with the executing fiber. /// </param> /// <returns> /// <see cref="FiberInstruction"/> or other scheduler specific instruction. /// </returns> private IEnumerator ExecuteYieldableTask(YieldableTask task) { object fiberResult = null; // TODO: Cleanup // // This uses internal setters to fake starting the fiber // and then uses internal Execute(). It should be possible to // use public APIs instead to: // 1. Set a fiber property to associate the task // 2. Set an exception handler on the FiberScheduler // 3. Retrieve the task in the handler from the fiber and set // the exeption // 4. Return from the handler without rethrowing // // This method could be removed then and the internal setters // removed as well. task.Fiber.Scheduler = scheduler; task.Fiber.Status = FiberStatus.Running; while (true) { try { // Throw here because the scheduler is disposed and will not // run anything else. No further access is valid. CancellationToken.ThrowIfCancellationRequested(); fiberResult = task.Fiber.Execute(); if (fiberResult is StopInstruction) { // Check for exceptions if (task.Fiber.IsFaulted) { task.FiberException = task.Fiber.Exception; } yield break; } } catch (System.Threading.OperationCanceledException ex) { // Fiber execution does not throw so the only exception // expected is the cancellation above. task.FiberException = ex; yield break; } yield return(fiberResult); } }
public void TestCancellationToken() { var start = DateTime.Now; var cancelSource = new CancellationTokenSource(); var backgroundFiberScheduler = SystemFiberScheduler.StartNew(cancelSource.Token); // Submit a task to the background scheduler and wait for it to complete var task = new YieldableTask(new YieldForSeconds(2)); task.RunSynchronously(new FiberTaskScheduler(backgroundFiberScheduler)); // Shutdown the scheduler thread cancelSource.Cancel(); backgroundFiberScheduler.SchedulerThread.Join(5000); var end = DateTime.Now; Assert.GreaterOrEqual(end - start, TimeSpan.FromSeconds(2)); Assert.LessOrEqual(end - start, TimeSpan.FromSeconds(3)); }
/// <summary> /// Execute the specified coroutine associated with a yieldable task. /// </summary> /// <remarks> /// Any exceptions that occur while executing the fiber will be /// associated with the specified task and rethrown by the framework. /// </remarks> /// <param name="task"> /// The task associated with the executing fiber. /// </param> /// <returns> /// <see cref="FiberInstruction"/> or other scheduler specific instruction. /// </returns> private IEnumerator ExecuteYieldableTask(YieldableTask task) { object fiberResult = null; // TODO: Cleanup // // This uses internal setters to fake starting the fiber // and then uses internal Execute(). It should be possible to // use public APIs instead to: // 1. Set a fiber property to associate the task // 2. Set an exception handler on the FiberScheduler // 3. Retrieve the task in the handler from the fiber and set // the exeption // 4. Return from the handler without rethrowing // // This method could be removed then and the internal setters // removed as well. task.Fiber.Scheduler = scheduler; task.Fiber.FiberState = FiberState.Running; while (true) { try { cancelSource.Token.ThrowIfCancellationRequested(); fiberResult = task.Fiber.Execute(); if (fiberResult is StopInstruction) { yield break; } } catch (Exception ex) { task.FiberException = ex; yield break; } yield return(fiberResult); } }
/// <summary> /// Execute the specified coroutine associated with a yieldable task. /// </summary> /// <remarks> /// Any exceptions that occur while executing the fiber will be /// associated with the specified task and rethrown by the framework. /// </remarks> /// <param name="task"> /// The task associated with the executing fiber. /// </param> /// <returns> /// <see cref="FiberInstruction"/> or other scheduler specific instruction. /// </returns> private IEnumerator ExecuteYieldableTask(YieldableTask task) { object fiberResult = null; // TODO: Cleanup // // This uses internal setters to fake starting the fiber // and then uses internal Execute(). It should be possible to // use public APIs instead to: // 1. Set a fiber property to associate the task // 2. Set an exception handler on the FiberScheduler // 3. Retrieve the task in the handler from the fiber and set // the exeption // 4. Return from the handler without rethrowing // // This method could be removed then and the internal setters // removed as well. task.Fiber.Scheduler = scheduler; task.Fiber.FiberState = FiberState.Running; while(true) { try { cancelSource.Token.ThrowIfCancellationRequested(); fiberResult = task.Fiber.Execute(); if(fiberResult is StopInstruction) yield break; } catch(Exception ex) { task.FiberException = ex; yield break; } yield return fiberResult; } }
/// <summary> /// Execute the specified coroutine associated with a yieldable task. /// </summary> /// <remarks> /// Any exceptions that occur while executing the fiber will be /// associated with the specified task and rethrown by the framework. /// </remarks> /// <param name="task"> /// The task associated with the executing fiber. /// </param> /// <returns> /// <see cref="FiberInstruction"/> or other scheduler specific instruction. /// </returns> private IEnumerator ExecuteYieldableTask(YieldableTask task) { object fiberResult = null; // TODO: Cleanup // // This uses internal setters to fake starting the fiber // and then uses internal Execute(). It should be possible to // use public APIs instead to: // 1. Set a fiber property to associate the task // 2. Set an exception handler on the FiberScheduler // 3. Retrieve the task in the handler from the fiber and set // the exeption // 4. Return from the handler without rethrowing // // This method could be removed then and the internal setters // removed as well. task.Fiber.Scheduler = scheduler; task.Fiber.Status = FiberStatus.Running; while(true) { try { // Throw here because the scheduler is disposed and will not // run anything else. No further access is valid. CancellationToken.ThrowIfCancellationRequested(); fiberResult = task.Fiber.Execute(); if(fiberResult is StopInstruction) { // Check for exceptions if (task.Fiber.IsFaulted) { task.FiberException = task.Fiber.Exception; } yield break; } } catch(System.Threading.OperationCanceledException ex) { // Fiber execution does not throw so the only exception // expected is the cancellation above. task.FiberException = ex; yield break; } yield return fiberResult; } }
/// <summary> /// Creates a new task and starts executing it. /// </summary> /// <returns> /// The new executing task. /// </returns> /// <param name='taskFactory'> /// Task factory to start with. /// </param> /// <param name='instruction'> /// The instruction to start. /// </param> /// <param name='cancellationToken'> /// Cancellation token. /// </param> /// <param name='creationOptions'> /// Creation options. /// </param> /// <param name='scheduler'> /// Scheduler. /// </param> public static Task StartNew(this TaskFactory taskFactory, FiberInstruction instruction, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler) { var task = new YieldableTask (instruction, cancellationToken, creationOptions); task.Start (scheduler); return task; }
/// <summary> /// Creates a new task and starts executing it. /// </summary> /// <returns> /// The new executing task. /// </returns> /// <param name='taskFactory'> /// Task factory to start with. /// </param> /// <param name='coroutine'> /// The coroutine to start. /// </param> /// <param name='cancellationToken'> /// Cancellation token. /// </param> /// <param name='creationOptions'> /// Creation options. /// </param> /// <param name='scheduler'> /// Scheduler. /// </param> public static Task StartNew(this TaskFactory taskFactory, IEnumerator coroutine, CancellationToken cancellationToken, TaskCreationOptions creationOptions, TaskScheduler scheduler) { var task = new YieldableTask (coroutine, cancellationToken, creationOptions); task.Start (scheduler); return task; }
/// <summary> /// Continues the task with a coroutine. /// </summary> /// <returns> /// The continued task. /// </returns> /// <param name='task'> /// Task to continue. /// </param> /// <param name='instruction'> /// The instruction to continue with. /// </param> /// <param name='cancellationToken'> /// Cancellation token. /// </param> /// <param name='continuationOptions'> /// Continuation options. /// </param> /// <param name='scheduler'> /// Scheduler to use when scheduling the task. /// </param> public static Task ContinueWith(this Task task, FiberInstruction instruction, CancellationToken cancellationToken, TaskContinuationOptions continuationOptions, TaskScheduler scheduler) { if (instruction == null) throw new ArgumentNullException ("instruction"); if (scheduler == null) throw new ArgumentNullException ("scheduler"); if (!(scheduler is FiberTaskScheduler)) throw new ArgumentException ("The scheduler for a YieldableTask must be a FiberTaskScheduler", "scheduler"); // This creates a continuation that runs on the default scheduler (e.g. ThreadPool) // where it's OK to wait on a child task to complete. The child task is scheduled // on the given scheduler and attached to the parent. //var outerScheduler = TaskScheduler.Current; //if(outerScheduler is MonoBehaviourTaskScheduler) // outerScheduler = TaskScheduler.Default; var outerScheduler = TaskScheduler.Default; return task.ContinueWith((Task antecedent) => { var yieldableTask = new YieldableTask(instruction, cancellationToken, TaskCreationOptions.AttachedToParent); yieldableTask.Start(scheduler); }, cancellationToken, continuationOptions, outerScheduler); }
private IEnumerator TestFuncTaskCoroutine() { var scheduler = new FiberTaskScheduler(); var task = new YieldableTask(() => new YieldForSeconds(2)); task.Start(scheduler); while (!task.IsCompleted) yield return FiberInstruction.YieldToAnyFiber; }
public void TestInstructionInTask() { var start = DateTime.Now; using (var backgroundFiberScheduler = SystemFiberScheduler.StartNew()) { // Submit a task to the background scheduler and wait for it to complete var task = new YieldableTask(new YieldForSeconds(2)); task.RunSynchronously(new FiberTaskScheduler(backgroundFiberScheduler)); } var end = DateTime.Now; Assert.GreaterOrEqual(end - start, TimeSpan.FromSeconds(2)); Assert.LessOrEqual(end - start, TimeSpan.FromSeconds(3)); }