FiberScheduler.cs
Go to the documentation of this file.
1 /*
2 
3 Author: Aaron Oneal, http://aarononeal.info
4 
5 Copyright (c) 2012 Spicy Pixel, http://spicypixel.com
6 
7 Permission is hereby granted, free of charge, to any person obtaining
8 a copy of this software and associated documentation files (the
9 "Software"), to deal in the Software without restriction, including
10 without limitation the rights to use, copy, modify, merge, publish,
11 distribute, sublicense, and/or sell copies of the Software, and to
12 permit persons to whom the Software is furnished to do so, subject to
13 the following conditions:
14 
15 The above copyright notice and this permission notice shall be
16 included in all copies or substantial portions of the Software.
17 
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 
26 */
27 using System;
28 using System.Threading;
29 
30 namespace SpicyPixel.Threading
31 {
44  public abstract class FiberScheduler : IFiberScheduler, IDisposable
45  {
49  [ThreadStatic]
50  private static FiberScheduler currentScheduler;
51 
53 
61  {
62  get { return cancelSource.Token; }
63  }
64 
74  public static FiberScheduler Current
75  {
76  get
77  {
78  if(currentScheduler == null)
79  {
80  // Make a new scheduler
81  SetCurrentScheduler(new SystemFiberScheduler(), true);
82  }
83 
84  return currentScheduler;
85  }
86 
87  // Private for now. Better not to let the caller set this and
88  // instead let it be set during execution. This way any
89  // new fibers inside a running fiber will use the same scheduler,
90  // and there is no risk of the caller changing it out from
91  // under the framework or wind up with a scheduler they didn't
92  // expect. For example, a caller in Unity might think they
93  // could set the current scheduler in Awake() and use the
94  // same scheduler in Update() even though another MonoBehaviour
95  // Awake() set it to something else because they all share
96  // the same thread. The current scheduler on a thread will
97  // get changed out automatically during Task.Execute()
98  // invoked by Update() invoked by Run().
99  /*private set
100  {
101  SetCurrentScheduler(value, false);
102  }*/
103  }
104 
105  static internal void SetCurrentScheduler(FiberScheduler scheduler, bool internalInvoke)
106  {
107  // Only allow scheduler changes on a thread when a fiber is not executing.
108  // Ignore this check if this is an internal invocation such as from
109  // Fiber.Execute() which needs to switch schedulers on demand.
110  if(!internalInvoke && Fiber.CurrentFiber != null)
111  throw new InvalidOperationException("The current scheduler for the thread cannot be changed from inside an executing fiber.");
112 
113  // Skip work if nothing to change
114  if(currentScheduler == scheduler)
115  return;
116 
117  // Assign the scheduler
118  currentScheduler = scheduler;
119 
120  // Update the synchronization context if it changed
121  if(currentScheduler != null && SynchronizationContext.Current != currentScheduler.SynchronizationContext)
122  SynchronizationContext.SetSynchronizationContext(currentScheduler.SynchronizationContext);
123  else if(currentScheduler == null && SynchronizationContext.Current != null)
124  SynchronizationContext.SetSynchronizationContext(null);
125  }
126 
133  private Thread schedulerThread;
134 
147  internal SynchronizationContext SynchronizationContext { get; private set; }
148 
149  /*
156  public bool IsSchedulerThread
157  {
158  get { return Thread.CurrentThread == schedulerThread; }
159  }
160  */
161 
168  public Thread SchedulerThread
169  {
170  get { return schedulerThread; }
171  }
172 
179  public bool AllowInlining { get; set; }
180 
184  protected FiberScheduler()
185  {
186  AllowInlining = true;
187  schedulerThread = Thread.CurrentThread;
188  SynchronizationContext = new FiberSchedulerSynchronizationContext(this);
189  }
190 
191  // Used by Fiber to invoke the protected methods
192  void IFiberScheduler.QueueFiber(Fiber fiber)
193  {
194  this.QueueFiber(fiber);
195  }
196 
197  // Used by Fiber to invoke the protected methods
198  void IFiberScheduler.AbortRequested(Fiber fiber)
199  {
200  this.AbortRequested(fiber);
201  }
202 
212  public void Run(Fiber fiber)
213  {
214  Run (fiber, CancellationToken.None, 0f);
215  }
216 
235  public virtual void Run(Fiber fiber, CancellationToken token, float updatesPerSecond = 0f)
236  {
237  throw new NotImplementedException();
238  }
239 
246  public void Run()
247  {
248  Run (CancellationToken.None);
249  }
250 
264  public virtual void Run(CancellationToken token, float updatesPerSecond = 0f)
265  {
266  Run (null, token, updatesPerSecond);
267  }
268 
282  protected abstract void QueueFiber(Fiber fiber);
283 
296  protected abstract void AbortRequested(Fiber fiber);
297 
313  {
314  return fiber.Execute();
315  }
316 
317  #region IDisposable implementation
318 
323  ~FiberScheduler()
324  {
325  Dispose(false);
326  }
327 
331  private bool isDisposed = false;
332 
344  public void Dispose()
345  {
346  Dispose(true);
347  GC.SuppressFinalize(this);
348  }
349 
360  protected virtual void Dispose(bool disposing)
361  {
362  // Do nothing if already called
363  if(isDisposed)
364  return;
365 
366  if(disposing)
367  {
368  // Free other state (managed objects).
369  cancelSource.Cancel();
370  }
371 
372  // Free your own state (unmanaged objects).
373  // Set large fields to null.
374 
375  // Mark disposed
376  isDisposed = true;
377  }
378  #endregion
379  }
380 }
381 
Schedules fibers for execution.
virtual void Run(CancellationToken token, float updatesPerSecond=0f)
Run the blocking scheduler loop and perform the specified number of updates per second.
This class is the system default implementation of a FiberScheduler and is capable of scheduling and ...
void Run(Fiber fiber)
Run the blocking scheduler loop and perform the specified number of updates per second.
A Fiber is a lightweight means of scheduling work that enables multiple units of processing to execut...
Represents a fiber instruction to be processed by a FiberScheduler.
void Run()
Run the blocking scheduler loop and perform the specified number of updates per second.
void Dispose()
Releases all resource used by the SpicyPixel.Threading.FiberScheduler object.
FiberScheduler()
Initializes a new instance of the SpicyPixel.Threading.FiberScheduler class.
virtual void Dispose(bool disposing)
Dispose the scheduler.
static FiberScheduler Current
Gets the default fiber scheduler for the thread.
Fiber scheduler synchronization context to support task synchronization across schedulers or other sy...
virtual void Run(Fiber fiber, CancellationToken token, float updatesPerSecond=0f)
Run the blocking scheduler loop and perform the specified number of updates per second.
FiberInstruction ExecuteFiber(Fiber fiber)
Executes the fiber until it ends or yields.
static Fiber CurrentFiber
Gets the currently executing fiber on this thread.
Definition: Fiber.cs:107