Start() public method

Start executing the fiber using the default scheduler on the thread.
public Start ( ) : void
return void
コード例 #1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="SpicyPixel.Threading.Fiber"/> class.
        /// </summary>
        /// <param name='func'>
        /// A non-blocking function that returns a <see cref="Fiber"/> when complete.
        /// </param>
        /// <param name='state'>
        /// State to pass to the function.
        /// </param>
        /// <param name="cancellationToken">Cancellation token.</param>
        /// <param name='scheduler'>
        /// A scheduler to execute the fiber on.
        /// </param>
        public Fiber StartNew(Func <object, FiberInstruction> func, object state, CancellationToken cancellationToken, FiberScheduler scheduler)
        {
            var fiber = new Fiber(func, state, cancellationToken);

            fiber.Start(scheduler);
            return(fiber);
        }
コード例 #2
0
        /// <summary>
        /// Start executing a new fiber using the specified scheduler.
        /// </summary>
        /// <returns>
        /// Returns a <see cref="Fiber"/>
        /// that can be yielded against to wait for the fiber to complete.
        /// </returns>
        /// <param name='coroutine'>
        /// A couroutine to execute on the fiber.
        /// </param>
        /// <param name="cancellationToken">Cancellation token.</param>
        /// <param name='scheduler'>
        /// A scheduler to execute the fiber on.
        /// </param>
        public Fiber StartNew(IEnumerator coroutine, CancellationToken cancellationToken, FiberScheduler scheduler)
        {
            var fiber = new Fiber(coroutine, cancellationToken);

            fiber.Start(scheduler);
            return(fiber);
        }
コード例 #3
0
        /// <summary>
        /// Start executing a new fiber using the default scheduler on the thread.
        /// </summary>
        /// <returns>
        /// Returns a <see cref="Fiber"/>
        /// that can be yielded against to wait for the fiber to complete.
        /// </returns>
        /// <param name='action'>
        /// A non-blocking action to execute on the fiber.
        /// </param>
        /// <param name="cancellationToken">Cancellation token.</param>
        /// <param name='scheduler'>
        /// A scheduler to execute the fiber on.
        /// </param>
        public Fiber StartNew(Action action, CancellationToken cancellationToken, FiberScheduler scheduler)
        {
            var fiber = new Fiber(action, cancellationToken);

            fiber.Start(scheduler);
            return(fiber);
        }
コード例 #4
0
        /// <summary>
        /// Start executing a new fiber using the default scheduler on the thread.
        /// </summary>
        /// <returns>
        /// Returns a <see cref="Fiber"/>
        /// that can be yielded against to wait for the fiber to complete.
        /// </returns>
        /// <param name='action'>
        /// A non-blocking action to execute on the fiber.
        /// </param>
        /// <param name='state'>
        /// State to pass to the action.
        /// </param>
        /// <param name="cancellationToken">Cancellation token.</param>
        /// <param name='scheduler'>
        /// A scheduler to execute the fiber on.
        /// </param>
        public Fiber StartNew(Action <object> action, object state, CancellationToken cancellationToken, FiberScheduler scheduler)
        {
            var fiber = new Fiber(action, state, cancellationToken);

            fiber.Start(scheduler);
            return(fiber);
        }
コード例 #5
0
        public void Execute()
        {
            // In case ran, faulted, canceled externally
            if (fiber.IsCompleted)
            {
                return;
            }

            // Cancel the fiber if criteria is not met
            if (!ContinuationStateCheck(options))
            {
                fiber.CancelContinuation();
                return;
            }

            fiber.Start(scheduler);
        }
コード例 #6
0
        /// <summary>
        /// Run the blocking scheduler loop and perform the specified number of updates per second.
        /// </summary>
        /// <remarks>
        /// Not all schedulers support a blocking run loop that can be invoked by the caller.
        /// The system scheduler is designed so that a custom run loop could be implemented
        /// by a derived type. Everything used to execute Run() is available to a derived scheduler.
        /// </remarks>
        /// <param name='fiber'>
        /// The optional fiber to start execution from. If this is <c>null</c>, the loop
        /// will continue to execute until cancelled. Otherwise, the loop will terminate
        /// when the fiber terminates.
        /// </param>
        /// <param name='updatesPerSecond'>
        /// Updates to all fibers per second. A value of <c>0</c> (the default) will execute fibers
        /// any time they are ready to do work instead of waiting to execute on a specific frequency.
        /// </param>
        /// <param name='token'>
        /// A cancellation token that can be used to stop execution.
        /// </param>
        public override void Run(Fiber fiber, CancellationToken token, float updatesPerSecond)
        {
            long frequencyTicks = (long)(updatesPerSecond * (float)TimeSpan.TicksPerSecond); // min time between updates (duration)
            long startTicks = 0; 		// start of update time (marker)
            long endTicks = 0; 			// end of update time (marker)
            long sleepTicks; 			// time to sleep (duration)
            long wakeTicks;				// ticks before wake (duration)
            int sleepMilliseconds;		// ms to sleep (duration)
            int wakeMilliseconds;		// ms before wake (duration)
            float wakeMarkerInSeconds;	// time of wake in seconds (marker)
            var mainFiberCompleteCancelSource = new CancellationTokenSource();

            if(isDisposed)
                throw new ObjectDisposedException(GetType().FullName);

            // Run is not re-entrant, make sure we're not running
            if(!runWaitHandle.WaitOne(0))
                throw new InvalidOperationException("Run is already executing and is not re-entrant");

            // Verify arguments
            if(updatesPerSecond < 0f)
                throw new ArgumentOutOfRangeException("updatesPerSecond", "The updatesPerSecond must be >= 0");

            // Get a base time for better precision
            long baseTicks = DateTime.Now.Ticks;

            // Build wait list to terminate execution
            var waitHandleList = new List<WaitHandle>(4);
            waitHandleList.Add(schedulerEventWaitHandle);
            waitHandleList.Add(disposeWaitHandle);

            if(token.CanBeCanceled)
                waitHandleList.Add(token.WaitHandle);

            try
            {
                if(fiber != null)
                {
                    // Add the main fiber to the wait list so when it completes
                    // the wait handle falls through.
                    waitHandleList.Add(mainFiberCompleteCancelSource.Token.WaitHandle);

                    // Start the main fiber if it isn't running yet
                    YieldUntilComplete waitOnFiber;
                    if(fiber.FiberState == FiberState.Unstarted)
                        waitOnFiber = fiber.Start(this);
                    else
                        waitOnFiber = new YieldUntilComplete(fiber);

                    // Start another fiber that waits on the main fiber to complete.
                    // When it does, it raises a cancellation.
                    Fiber.StartNew(CancelWhenComplete(waitOnFiber, mainFiberCompleteCancelSource), this);
                }

                WaitHandle[] waitHandles = waitHandleList.ToArray();
                waitHandleList.Remove(schedulerEventWaitHandle);
                WaitHandle[] sleepWaitHandles = waitHandleList.ToArray();

                runWaitHandle.Reset();

                while(true)
                {
                    // Stop executing if cancelled
                    if((token.CanBeCanceled && token.IsCancellationRequested) || mainFiberCompleteCancelSource.IsCancellationRequested || disposeWaitHandle.WaitOne(0))
                        return;

                    // Snap current time
                    startTicks = DateTime.Now.Ticks;

                    // Update using this time marker (and convert ticks to s)
                    Update((float)((double)(startTicks - baseTicks) / (double)TimeSpan.TicksPerSecond));

                    // Only sleep to next frequency cycle if one was specified
                    if(updatesPerSecond > 0f)
                    {
                        // Snap end time
                        endTicks = DateTime.Now.Ticks;

                        // Sleep at least until next update
                        sleepTicks = frequencyTicks - (endTicks - startTicks);
                        if(sleepTicks > 0)
                        {
                            sleepMilliseconds = (int)(sleepTicks / TimeSpan.TicksPerMillisecond);

                            WaitHandle.WaitAny(sleepWaitHandles, sleepMilliseconds);

                            // Stop executing if cancelled
                            if((token.CanBeCanceled && token.IsCancellationRequested) || mainFiberCompleteCancelSource.IsCancellationRequested || disposeWaitHandle.WaitOne(0))
                                return;
                        }
                    }

                    // Now keep sleeping until it's time to update
                    while(ExecutingFiberCount == 0)
                    {
                        // Assume we wait forever (e.g. until a signal)
                        wakeMilliseconds = -1;

                        // If there are sleeping fibers, then set a wake time
                        if(GetNextFiberWakeTime(out wakeMarkerInSeconds))
                        {
                            wakeTicks = baseTicks;
                            wakeTicks += (long)((double)wakeMarkerInSeconds * (double)TimeSpan.TicksPerSecond);
                            wakeTicks -= DateTime.Now.Ticks;

                            // If there was a waiting fiber and it's already past time to awake then stop waiting
                            if(wakeTicks <= 0)
                                break;

                            wakeMilliseconds = (int)(wakeTicks / TimeSpan.TicksPerMillisecond);
                        }

                        // There was no waiting fiber and we will wait for another signal,
                        // or there was a waiting fiber and we wait until that time.
                        WaitHandle.WaitAny(waitHandles, wakeMilliseconds);

                        // Stop executing if cancelled
                        if((token.CanBeCanceled && token.IsCancellationRequested) || mainFiberCompleteCancelSource.IsCancellationRequested || disposeWaitHandle.WaitOne(0))
                            return;
                    }
                }
            }
            finally
            {
                // Clear queues
                Fiber deqeueFiber;
                while(executingFibers.TryDequeue(out deqeueFiber));

                Tuple<Fiber, float> dequeueSleepingFiber;
                while(sleepingFibers.TryDequeue(out dequeueSleepingFiber));

                // Reset time
                currentTime = 0f;

                // Set for dispose
                runWaitHandle.Set();
            }
        }
コード例 #7
0
        /// <summary>
        /// Run the blocking scheduler loop and perform the specified number of updates per second.
        /// </summary>
        /// <remarks>
        /// Not all schedulers support a blocking run loop that can be invoked by the caller.
        /// The system scheduler is designed so that a custom run loop could be implemented
        /// by a derived type. Everything used to execute Run() is available to a derived scheduler.
        /// </remarks>
        /// <param name='fiber'>
        /// The optional fiber to start execution from. If this is <c>null</c>, the loop
        /// will continue to execute until cancelled. Otherwise, the loop will terminate
        /// when the fiber terminates.
        /// </param>
        /// <param name='updatesPerSecond'>
        /// Updates to all fibers per second. A value of <c>0</c> (the default) will execute fibers
        /// any time they are ready to do work instead of waiting to execute on a specific frequency.
        /// </param>
        /// <param name='token'>
        /// A cancellation token that can be used to stop execution.
        /// </param>
        public override void Run(Fiber fiber, CancellationToken token, float updatesPerSecond)
        {
            long  frequencyTicks = (long)(updatesPerSecond * (float)TimeSpan.TicksPerSecond); // min time between updates (duration)
            long  startTicks     = 0;                                                         // start of update time (marker)
            long  endTicks       = 0;                                                         // end of update time (marker)
            long  sleepTicks;                                                                 // time to sleep (duration)
            long  wakeTicks;                                                                  // ticks before wake (duration)
            int   sleepMilliseconds;                                                          // ms to sleep (duration)
            int   wakeMilliseconds;                                                           // ms before wake (duration)
            float wakeMarkerInSeconds;                                                        // time of wake in seconds (marker)
            var   mainFiberCompleteCancelSource = new CancellationTokenSource();

            if (isDisposed)
            {
                throw new ObjectDisposedException(GetType().FullName);
            }

            // Run is not re-entrant, make sure we're not running
            if (!runWaitHandle.WaitOne(0))
            {
                throw new InvalidOperationException("Run is already executing and is not re-entrant");
            }

            // Verify arguments
            if (updatesPerSecond < 0f)
            {
                throw new ArgumentOutOfRangeException("updatesPerSecond", "The updatesPerSecond must be >= 0");
            }

            // Get a base time for better precision
            long baseTicks = DateTime.Now.Ticks;

            // Build wait list to terminate execution
            var waitHandleList = new List <WaitHandle>(4);

            waitHandleList.Add(schedulerEventWaitHandle);
            waitHandleList.Add(disposeWaitHandle);

            if (token.CanBeCanceled)
            {
                waitHandleList.Add(token.WaitHandle);
            }

            try
            {
                if (fiber != null)
                {
                    // Add the main fiber to the wait list so when it completes
                    // the wait handle falls through.
                    waitHandleList.Add(mainFiberCompleteCancelSource.Token.WaitHandle);

                    // Start the main fiber if it isn't running yet
                    YieldUntilComplete waitOnFiber;
                    if (fiber.FiberState == FiberState.Unstarted)
                    {
                        waitOnFiber = fiber.Start(this);
                    }
                    else
                    {
                        waitOnFiber = new YieldUntilComplete(fiber);
                    }

                    // Start another fiber that waits on the main fiber to complete.
                    // When it does, it raises a cancellation.
                    Fiber.StartNew(CancelWhenComplete(waitOnFiber, mainFiberCompleteCancelSource), this);
                }

                WaitHandle[] waitHandles = waitHandleList.ToArray();
                waitHandleList.Remove(schedulerEventWaitHandle);
                WaitHandle[] sleepWaitHandles = waitHandleList.ToArray();

                runWaitHandle.Reset();

                while (true)
                {
                    // Stop executing if cancelled
                    if ((token.CanBeCanceled && token.IsCancellationRequested) || mainFiberCompleteCancelSource.IsCancellationRequested || disposeWaitHandle.WaitOne(0))
                    {
                        return;
                    }

                    // Snap current time
                    startTicks = DateTime.Now.Ticks;

                    // Update using this time marker (and convert ticks to s)
                    Update((float)((double)(startTicks - baseTicks) / (double)TimeSpan.TicksPerSecond));

                    // Only sleep to next frequency cycle if one was specified
                    if (updatesPerSecond > 0f)
                    {
                        // Snap end time
                        endTicks = DateTime.Now.Ticks;

                        // Sleep at least until next update
                        sleepTicks = frequencyTicks - (endTicks - startTicks);
                        if (sleepTicks > 0)
                        {
                            sleepMilliseconds = (int)(sleepTicks / TimeSpan.TicksPerMillisecond);

                            WaitHandle.WaitAny(sleepWaitHandles, sleepMilliseconds);

                            // Stop executing if cancelled
                            if ((token.CanBeCanceled && token.IsCancellationRequested) || mainFiberCompleteCancelSource.IsCancellationRequested || disposeWaitHandle.WaitOne(0))
                            {
                                return;
                            }
                        }
                    }

                    // Now keep sleeping until it's time to update
                    while (ExecutingFiberCount == 0)
                    {
                        // Assume we wait forever (e.g. until a signal)
                        wakeMilliseconds = -1;

                        // If there are sleeping fibers, then set a wake time
                        if (GetNextFiberWakeTime(out wakeMarkerInSeconds))
                        {
                            wakeTicks  = baseTicks;
                            wakeTicks += (long)((double)wakeMarkerInSeconds * (double)TimeSpan.TicksPerSecond);
                            wakeTicks -= DateTime.Now.Ticks;

                            // If there was a waiting fiber and it's already past time to awake then stop waiting
                            if (wakeTicks <= 0)
                            {
                                break;
                            }

                            wakeMilliseconds = (int)(wakeTicks / TimeSpan.TicksPerMillisecond);
                        }

                        // There was no waiting fiber and we will wait for another signal,
                        // or there was a waiting fiber and we wait until that time.
                        WaitHandle.WaitAny(waitHandles, wakeMilliseconds);

                        // Stop executing if cancelled
                        if ((token.CanBeCanceled && token.IsCancellationRequested) || mainFiberCompleteCancelSource.IsCancellationRequested || disposeWaitHandle.WaitOne(0))
                        {
                            return;
                        }
                    }
                }
            }
            finally
            {
                // Clear queues
                Fiber deqeueFiber;
                while (executingFibers.TryDequeue(out deqeueFiber))
                {
                    ;
                }

                Tuple <Fiber, float> dequeueSleepingFiber;
                while (sleepingFibers.TryDequeue(out dequeueSleepingFiber))
                {
                    ;
                }

                // Reset time
                currentTime = 0f;

                // Set for dispose
                runWaitHandle.Set();
            }
        }
コード例 #8
0
 public void TestYieldToFiber()
 {
     using (var backgroundFiberScheduler = SystemFiberScheduler.StartNew()) {
         backgroundFiberScheduler.AllowInlining = true;
         var f1 = new Fiber(IncrementerCoroutine1());
         f1.Start(backgroundFiberScheduler);
         backgroundFiberScheduler.SchedulerThread.Join(2000);
     }
     Assert.AreEqual(yieldToFiberCounter2, yieldToFiberCounter1 * 2);
 }
コード例 #9
0
 /// <summary>
 /// Start executing a new fiber using the specified scheduler.
 /// </summary>
 /// <returns>
 /// Returns a <see cref="Fiber"/>
 /// that can be yielded against to wait for the fiber to complete.
 /// </returns>
 /// <param name='coroutine'>
 /// A couroutine to execute on the fiber.
 /// </param>
 /// <param name="cancellationToken">Cancellation token.</param>
 /// <param name='scheduler'>
 /// A scheduler to execute the fiber on.
 /// </param>
 public Fiber StartNew(IEnumerator coroutine, CancellationToken cancellationToken, FiberScheduler scheduler)
 {
     var fiber = new Fiber(coroutine, cancellationToken);
     fiber.Start(scheduler);
     return fiber;
 }
コード例 #10
0
 /// <summary>
 /// Initializes a new instance of the <see cref="SpicyPixel.Threading.Fiber"/> class.
 /// </summary>
 /// <param name='func'>
 /// A non-blocking function that returns a <see cref="Fiber"/> when complete.
 /// </param>
 /// <param name='state'>
 /// State to pass to the function.
 /// </param>
 /// <param name="cancellationToken">Cancellation token.</param>
 /// <param name='scheduler'>
 /// A scheduler to execute the fiber on.
 /// </param>
 public Fiber StartNew(Func<object, FiberInstruction> func, object state, CancellationToken cancellationToken, FiberScheduler scheduler)
 {
     var fiber = new Fiber(func, state, cancellationToken);
     fiber.Start(scheduler);
     return fiber;
 }
コード例 #11
0
 /// <summary>
 /// Start executing a new fiber using the default scheduler on the thread.
 /// </summary>
 /// <returns>
 /// Returns a <see cref="Fiber"/>
 /// that can be yielded against to wait for the fiber to complete.
 /// </returns>
 /// <param name='action'>
 /// A non-blocking action to execute on the fiber.
 /// </param>
 /// <param name='state'>
 /// State to pass to the action.
 /// </param>
 /// <param name="cancellationToken">Cancellation token.</param>
 /// <param name='scheduler'>
 /// A scheduler to execute the fiber on.
 /// </param>
 public Fiber StartNew(Action<object> action, object state, CancellationToken cancellationToken, FiberScheduler scheduler)
 {
     var fiber = new Fiber(action, state, cancellationToken);
     fiber.Start(scheduler);
     return fiber;
 }
コード例 #12
0
 /// <summary>
 /// Start executing a new fiber using the default scheduler on the thread.
 /// </summary>
 /// <returns>
 /// Returns a <see cref="Fiber"/>
 /// that can be yielded against to wait for the fiber to complete.
 /// </returns>
 /// <param name='action'>
 /// A non-blocking action to execute on the fiber.
 /// </param>
 /// <param name="cancellationToken">Cancellation token.</param>
 /// <param name='scheduler'>
 /// A scheduler to execute the fiber on.
 /// </param>
 public Fiber StartNew(Action action, CancellationToken cancellationToken, FiberScheduler scheduler)
 {
     var fiber = new Fiber(action, cancellationToken);
     fiber.Start(scheduler);
     return fiber;
 }