@@ -22,7 +22,7 @@ public bool Cancel(bool onlyIfNotRunning)
2222 if ( ! onlyIfNotRunning || ! isRunning )
2323 ts . Cancel ( ) ;
2424
25- return ! isRunning ;
25+ return ! isRunning ;
2626 }
2727
2828 public bool Cancel ( )
@@ -57,16 +57,6 @@ protected CancellableTask(CancellationToken token)
5757 {
5858 }
5959
60- public static CancellableTask Prepare ( Action action )
61- {
62- var ts = new CancellationTokenSource ( ) ;
63- var token = ts . Token ;
64- return new CancellableTask ( action , token )
65- {
66- TokenSource = ts // Could potentially call cancel before run actually happens.
67- } ;
68- }
69-
7060 public static CancellableTask Start ( TimeSpan delay , Action action = null , TaskScheduler scheduler = null )
7161 {
7262 CancellableTask cancellable ;
@@ -88,13 +78,26 @@ public static CancellableTask Start(TimeSpan delay, Action action = null, TaskSc
8878
8979 if ( delay == TimeSpan . Zero )
9080 {
91- cancellable . Start ( scheduler ) ;
81+ cancellable . Start ( scheduler ) ;
9282 }
9383 else
9484 {
95- cancellable . ContinueWith ( t => cancellable . Cancel ( ) ) ; // If this is arbitrarily run before the delay, then cancel the delay.
85+ int runState = 0 ;
86+
87+ cancellable
88+ . ContinueWith ( t =>
89+ {
90+ // If this is arbitrarily run before the delay, then cancel the delay.
91+ if ( Interlocked . Increment ( ref runState ) < 2 )
92+ cancellable . Cancel ( ) ;
93+ } ) ;
94+
9695 Delay ( delay , token )
97- . OnFullfilled ( ( ) => cancellable . EnsureStarted ( scheduler ) ) ;
96+ . OnFullfilled ( ( ) =>
97+ {
98+ Interlocked . Increment ( ref runState ) ;
99+ cancellable . EnsureStarted ( scheduler ) ;
100+ } ) ;
98101 }
99102 }
100103
@@ -113,22 +116,29 @@ public static CancellableTask Start(Action action, TimeSpan? delay = null, TaskS
113116 }
114117
115118 /// <summary>
116- /// A Task sub-class that simplifies cancelling.
119+ /// A Task<T> sub-class that simplifies cancelling.
117120 /// </summary>
118121 public class CancellableTask < T > : Task < T > , ICancellable
119122 {
120123 protected CancellationTokenSource TokenSource ;
121124
122- public bool Cancel ( )
125+ public bool Cancel ( bool onlyIfNotRunning )
123126 {
124127 var ts = Interlocked . Exchange ( ref TokenSource , null ) ; // Cancel can only be called once.
125128
126129 if ( ts == null || ts . IsCancellationRequested || IsCanceled || IsFaulted || IsCompleted )
127130 return false ;
128131
129- ts . Cancel ( ) ;
132+ var isRunning = Status == TaskStatus . Running ;
133+ if ( ! onlyIfNotRunning || ! isRunning )
134+ ts . Cancel ( ) ;
130135
131- return Status != TaskStatus . Running ; // should never be running, but just to be correct...
136+ return ! isRunning ;
137+ }
138+
139+ public bool Cancel ( )
140+ {
141+ return Cancel ( false ) ;
132142 }
133143
134144 public void Dispose ( )
@@ -146,20 +156,10 @@ protected CancellableTask(Func<T> action, CancellationToken token)
146156 {
147157 }
148158
149- public static CancellableTask < T > Prepare ( Func < T > action )
150- {
151- var ts = new CancellationTokenSource ( ) ;
152- var token = ts . Token ;
153- return new CancellableTask < T > ( action , token )
154- {
155- TokenSource = ts // Could potentially call cancel before run actually happens.
156- } ;
157- }
158-
159-
160- public static CancellableTask < T > Start ( TimeSpan delay , Func < T > action = null )
159+ public static CancellableTask < T > Start ( TimeSpan delay , Func < T > action = null , TaskScheduler scheduler = null )
161160 {
162161 CancellableTask < T > cancellable ;
162+ scheduler = scheduler ?? TaskScheduler . Default ;
163163
164164 if ( delay < TimeSpan . Zero )
165165 {
@@ -177,28 +177,40 @@ public static CancellableTask<T> Start(TimeSpan delay, Func<T> action = null)
177177
178178 if ( delay == TimeSpan . Zero )
179179 {
180- cancellable . Start ( ) ;
180+ cancellable . Start ( scheduler ) ;
181181 }
182182 else
183183 {
184- cancellable . ContinueWith ( t => cancellable . Cancel ( ) ) ; // If this is arbitrarily run before the delay, then cancel the delay.
184+ int runState = 0 ;
185+
186+ cancellable
187+ . ContinueWith ( t =>
188+ {
189+ // If this is arbitrarily run before the delay, then cancel the delay.
190+ if ( Interlocked . Increment ( ref runState ) < 2 )
191+ cancellable . Cancel ( ) ;
192+ } ) ;
193+
185194 Delay ( delay , token )
186- . OnFullfilled ( ( ) => cancellable . Start ( ) ) ;
195+ . OnFullfilled ( ( ) =>
196+ {
197+ Interlocked . Increment ( ref runState ) ;
198+ cancellable . EnsureStarted ( scheduler ) ;
199+ } ) ;
187200 }
188201 }
189202
190203 return cancellable ;
191204 }
192205
193- public static CancellableTask < T > Start ( int millisecondsDelay , Func < T > action )
206+ public static CancellableTask < T > Start ( int millisecondsDelay , Func < T > action = null )
194207 {
195208 return Start ( TimeSpan . FromMilliseconds ( millisecondsDelay ) , action ) ;
196209 }
197210
198- public static CancellableTask < T > Start ( Func < T > action )
211+ public static CancellableTask < T > Start ( Func < T > action , TimeSpan ? delay = null , TaskScheduler scheduler = null )
199212 {
200- return Start ( TimeSpan . Zero , action ) ;
213+ return Start ( delay ?? TimeSpan . Zero , action , scheduler ) ;
201214 }
202215 }
203-
204216}
0 commit comments