Advertisement
Guest User

Untitled

a guest
Mar 30th, 2013
1,300
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 8.17 KB | None | 0 0
  1. using System;
  2. using System.Threading.Tasks;
  3. using System.Threading;
  4. using System.Collections;
  5.  
  6.  
  7. namespace ConsoleApplication1
  8. {
  9.     public static class TaskUtils
  10.     {
  11.         private class TaskBuilder<T> : IDisposable
  12.         {
  13.             private readonly TaskCompletionSource<T> completionSource;
  14.             private readonly CancellationToken cancellation;
  15.             private volatile IEnumerator stateMachine;
  16.             private volatile int status;
  17.             private volatile Task currentTask;
  18.  
  19.             public Task<T> Task { get { return this.completionSource.Task; } }
  20.             public TaskStatus Status { get { return (TaskStatus)this.status; } }
  21.  
  22.             public TaskBuilder(IEnumerator enumerator, object state, TaskCreationOptions creationFlags = TaskCreationOptions.None, CancellationToken cancellationToken = default(CancellationToken))
  23.             {
  24.                 if (enumerator == null)
  25.                     throw new ArgumentNullException("enumerator");
  26.  
  27.                 this.stateMachine = enumerator;
  28.                 this.completionSource = new TaskCompletionSource<T>(state, creationFlags);
  29.                 this.cancellation = cancellationToken;
  30.                 this.status = (int)TaskStatus.WaitingForActivation;
  31.             }
  32.  
  33.             private void Next()
  34.             {
  35.                 try
  36.                 {
  37.                     cancellation.ThrowIfCancellationRequested();
  38.  
  39.                     var hasNext = stateMachine.MoveNext();
  40.                     var nextValue = hasNext ? this.stateMachine.Current : null;
  41.                     if (!hasNext)
  42.                     {
  43.                         // yielded break
  44.                         Interlocked.CompareExchange(ref this.status, (int)TaskStatus.RanToCompletion, (int)TaskStatus.Running);
  45.                         completionSource.TrySetResult(default(T));
  46.                     }
  47.                     else if (nextValue is Task)
  48.                     {
  49.                         // yielded task
  50.                         var nextTask = (Task)nextValue;
  51.                         nextTask.ContinueWith((t) =>
  52.                         {
  53.                             Interlocked.CompareExchange(ref this.currentTask, null, t);
  54.  
  55.                             if (t.IsFaulted)
  56.                             {
  57.                                 Interlocked.CompareExchange(ref this.status, (int)TaskStatus.Faulted, (int)TaskStatus.Running);
  58.                                 this.completionSource.TrySetException(t.Exception);
  59.                                 this.Dispose();
  60.                             }
  61.                             else if (t.IsCanceled)
  62.                             {
  63.                                 Interlocked.CompareExchange(ref this.status, (int)TaskStatus.Canceled, (int)TaskStatus.Running);
  64.                                 this.completionSource.TrySetCanceled();
  65.                                 this.Dispose();
  66.                             }
  67.                             else
  68.                                 this.Next();
  69.                         }, CancellationToken.None, TaskContinuationOptions.LongRunning, TaskScheduler.Current);
  70.  
  71.                         // save next task in root's state, so GC would't collect it
  72.                         this.currentTask = nextTask;
  73.                     }
  74.                     else
  75.                     {
  76.                         // yeilded value
  77.                         Interlocked.CompareExchange(ref this.status, (int)TaskStatus.Faulted, (int)TaskStatus.Running);
  78.                         this.completionSource.TrySetResult((T)nextValue);
  79.                     }
  80.                 }
  81.                 catch (ThreadAbortException) { throw; }
  82.                 catch (OutOfMemoryException) { throw; }
  83.                 catch (OperationCanceledException)
  84.                 {
  85.                     this.completionSource.TrySetCanceled();
  86.                 }
  87.                 catch (Exception e)
  88.                 {
  89.                     Interlocked.CompareExchange(ref this.status, (int)TaskStatus.Faulted, (int)TaskStatus.Running);
  90.                     this.completionSource.TrySetException(e);
  91.                 }
  92.  
  93.                 if (this.status == (int)TaskStatus.RanToCompletion || this.status == (int)TaskStatus.Faulted || this.status == (int)TaskStatus.Canceled)
  94.                     this.Dispose();
  95.             }
  96.  
  97.             public void Start()
  98.             {
  99.                 if (Interlocked.CompareExchange(ref this.status, (int)TaskStatus.Running, (int)TaskStatus.WaitingForActivation) != (int)TaskStatus.WaitingForActivation)
  100.                     return;
  101.  
  102.                 this.currentTask = System.Threading.Tasks.Task.Factory.StartNew(this.Next, this.cancellation);
  103.             }
  104.             public void StartNow()
  105.             {
  106.                 if (Interlocked.CompareExchange(ref this.status, (int)TaskStatus.Running, (int)TaskStatus.WaitingForActivation) != (int)TaskStatus.WaitingForActivation)
  107.                     return;
  108.  
  109.                 this.Next();
  110.             }
  111.  
  112.             #region IDisposable Members
  113.  
  114.             public void Dispose()
  115.             {
  116.                 Interlocked.CompareExchange(ref this.status, (int)TaskStatus.Canceled, (int)TaskStatus.WaitingForActivation);
  117.                 Interlocked.CompareExchange(ref this.status, (int)TaskStatus.Canceled, (int)TaskStatus.Running);
  118.                 try
  119.                 {
  120.                     var s = Interlocked.Exchange(ref this.stateMachine, null);
  121.                     if (s is IDisposable)
  122.                         (s as IDisposable).Dispose();
  123.                 }
  124.                 catch (ThreadAbortException) { throw; }
  125.                 catch (OutOfMemoryException) { throw; }
  126.                 catch (Exception e)
  127.                 {
  128.                     // Log.Error("An error while disposing builder's state machine", e);
  129.                 }
  130.  
  131.                 this.completionSource.TrySetCanceled();
  132.             }
  133.  
  134.             #endregion
  135.  
  136.             public override string ToString()
  137.             {
  138.                 return string.Format("TaskBuilder, Status={0}, Generator={1}", this.Status, this.stateMachine);
  139.             }
  140.         }
  141.  
  142.         public static Task FromIterator(Func<object, IEnumerable> iteratorFn, object state, TaskCreationOptions creationFlags = TaskCreationOptions.None, CancellationToken cancellationToken = default(CancellationToken))
  143.         {
  144.             return FromIterator<object>(iteratorFn, state, creationFlags, cancellationToken);
  145.         }
  146.         public static Task FromIterator(IEnumerable iterator, TaskCreationOptions creationFlags = TaskCreationOptions.None, CancellationToken cancellationToken = default(CancellationToken))
  147.         {
  148.             return FromIterator<object>(iterator, null, creationFlags, cancellationToken);
  149.         }
  150.         public static Task<T> FromIterator<T>(Func<object, IEnumerable> iteratorFn, object state, TaskCreationOptions creationFlags = TaskCreationOptions.None, CancellationToken cancellationToken = default(CancellationToken))
  151.         {
  152.             if (iteratorFn == null)
  153.                 throw new ArgumentNullException("iteratorFn");
  154.  
  155.             var iterator = iteratorFn(state);
  156.  
  157.             return FromIterator<T>(iterator, state, creationFlags, cancellationToken);
  158.         }
  159.         public static Task<T> FromIterator<T>(IEnumerable iterator, object state, TaskCreationOptions creationFlags = TaskCreationOptions.None, CancellationToken cancellationToken = default(CancellationToken))
  160.         {
  161.             if (iterator == null)
  162.                 throw new ArgumentNullException("iterator");
  163.  
  164.             var isLongRunning = (creationFlags & TaskCreationOptions.LongRunning) == TaskCreationOptions.LongRunning;
  165.             if (isLongRunning)
  166.                 creationFlags = creationFlags ^ TaskCreationOptions.LongRunning; // remove LongRunning flag
  167.  
  168.  
  169.             var enumerator = iterator.GetEnumerator();
  170.             var builder = new TaskBuilder<T>(enumerator, state, creationFlags, cancellationToken);
  171.  
  172.             // start state machine
  173.             if (isLongRunning)
  174.                 builder.Start();
  175.             else
  176.                 builder.StartNow();
  177.  
  178.             // return root task
  179.             return builder.Task;
  180.         }
  181.  
  182.     }
  183. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement