Skip to content

Commit 848cdb8

Browse files
author
Oren (electricessence)
committed
Updates to CancellableTask.
1 parent 8e79668 commit 848cdb8

2 files changed

Lines changed: 50 additions & 38 deletions

File tree

CancellableTask.cs

Lines changed: 49 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -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&lt;T&gt; 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
}

Open.Threading.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
Part of the "Open" set of libraries.</Description>
1111
<PackageLicenseUrl>https://github.com/electricessence/Open.Threading/blob/master/LISCENSE.md</PackageLicenseUrl>
1212
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
13-
<Version>1.1.2</Version>
13+
<Version>1.1.3</Version>
1414
<AssemblyVersion>1.0.0.1</AssemblyVersion>
1515
<FileVersion>1.0.0.1</FileVersion>
1616
<Copyright>https://github.com/electricessence/Open.Threading/blob/master/LISCENSE.md</Copyright>

0 commit comments

Comments
 (0)