PauseOrCancelTokenSource
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
4
down vote
favorite
I added this implementation of PauseToken and PauseTokenSource to my project from this MSDN blog post: Cooperatively pausing async methods
Since I will usually be passing in both a PauseToken and a CancellationToken into async methods, I am trying to encapsulate both of them into a single class, PauseOrCancelToken, created by PauseOrCancelTokenSource. I'm not entirely sure if I have implemented it correctly, although it does work as intended. Just wondering if I overlooked anything important that someone else might be able to spot.
public partial class PauseCancelForm : Form
private PauseOrCancelTokenSource pcts = new PauseOrCancelTokenSource();
public PauseCancelForm()
InitializeComponent();
private void StartButton_Click(object sender, EventArgs e)
Task.Run(() =>
DoSomeAsyncStuff(pcts.Token).Wait();
);
private async Task DoSomeAsyncStuff(PauseOrCancelToken pct)
var proxies = new List<Proxy>();
var judges = new List<ProxyJudge>();
for (int i = 0; i < 100; i++)
proxies.Add(new Proxy("127.0.0." + RandomUtility.GetRandomInt(1, 5), 8888));
judges.Add(new ProxyJudge("http://azenv.net"));
await ProxyTester.Start(proxies, judges, pct);
private void PauseButton_Click(object sender, EventArgs e)
pcts.Pause();
private void StopButton_Click(object sender, EventArgs e)
pcts.Cancel();
public class PauseOrCancelTokenSource
private PauseTokenSource pts = new PauseTokenSource();
private CancellationTokenSource cts = new CancellationTokenSource();
public PauseOrCancelToken Token get return new PauseOrCancelToken(pts, cts);
public void Pause()
pts.IsPaused = true;
public void Cancel()
cts.Cancel();
public class PauseOrCancelToken
private PauseToken pt;
private CancellationToken ct;
public PauseOrCancelToken(PauseTokenSource pts, CancellationTokenSource cts)
this.pt = pts.Token;
this.ct = cts.Token;
public async Task PauseIfRequested()
await pt.WaitWhilePausedAsync();
public void CancelIfRequested()
ct.ThrowIfCancellationRequested();
Example
public class ProxyTester
public async static Task Start(List<Proxy> proxies, List<ProxyJudge> judges, PauseOrCancelToken pct, List<ProxyTest> tests = null)
if (tests == null)
tests = new List<ProxyTest>();
//Get external IP to check if proxy is anonymous.
var publicIp = await WebUtility.GetPublicIP();
//Validate proxy judges.
var tasks = new List<Task>();
foreach (var judge in judges)
tasks.Add(Task.Run(async () =>
judge.IsValid = await judge.TestValidityAsync();
await pct.PauseIfRequested();
pct.CancelIfRequested();
));
await Task.WhenAll(tasks);
var validJudges = from judge in judges
where judge.IsValid
select judge;
if (validJudges.Count() == 0)
throw new Exception("No valid judges loaded.");
//Validate proxy tests.
tasks.Clear();
foreach (var test in tests)
tasks.Add(Task.Run(async () =>
test.IsValid = await test.TestValidityAsync();
await pct.PauseIfRequested();
pct.CancelIfRequested();
));
await Task.WhenAll(tasks);
var validTests = from test in tests
where test.IsValid
select test;
//Test proxies with a random, valid proxy judge. If valid, test with all valid proxy tests.
tasks.Clear();
foreach (var proxy in proxies)
tasks.Add(Task.Run(async () =>
proxy.IsValid = await proxy.TestValidityAsync(validJudges.ElementAt(RandomUtility.GetRandomInt(0, validJudges.Count())));
await pct.PauseIfRequested();
pct.CancelIfRequested();
if (proxy.IsValid)
proxy.TestedSites.AddRange(validTests);
var childTasks = new List<Task>();
foreach (var test in validTests)
childTasks.Add(Task.Run(async () =>
proxy.TestedSites.ElementAt(proxy.TestedSites.IndexOf(test)).IsValid = await proxy.TestValidityAsync(test);
await pct.PauseIfRequested();
pct.CancelIfRequested();
));
await Task.WhenAll(childTasks);
));
await Task.WhenAll(tasks);
c# beginner asynchronous winforms task-parallel-library
add a comment |Â
up vote
4
down vote
favorite
I added this implementation of PauseToken and PauseTokenSource to my project from this MSDN blog post: Cooperatively pausing async methods
Since I will usually be passing in both a PauseToken and a CancellationToken into async methods, I am trying to encapsulate both of them into a single class, PauseOrCancelToken, created by PauseOrCancelTokenSource. I'm not entirely sure if I have implemented it correctly, although it does work as intended. Just wondering if I overlooked anything important that someone else might be able to spot.
public partial class PauseCancelForm : Form
private PauseOrCancelTokenSource pcts = new PauseOrCancelTokenSource();
public PauseCancelForm()
InitializeComponent();
private void StartButton_Click(object sender, EventArgs e)
Task.Run(() =>
DoSomeAsyncStuff(pcts.Token).Wait();
);
private async Task DoSomeAsyncStuff(PauseOrCancelToken pct)
var proxies = new List<Proxy>();
var judges = new List<ProxyJudge>();
for (int i = 0; i < 100; i++)
proxies.Add(new Proxy("127.0.0." + RandomUtility.GetRandomInt(1, 5), 8888));
judges.Add(new ProxyJudge("http://azenv.net"));
await ProxyTester.Start(proxies, judges, pct);
private void PauseButton_Click(object sender, EventArgs e)
pcts.Pause();
private void StopButton_Click(object sender, EventArgs e)
pcts.Cancel();
public class PauseOrCancelTokenSource
private PauseTokenSource pts = new PauseTokenSource();
private CancellationTokenSource cts = new CancellationTokenSource();
public PauseOrCancelToken Token get return new PauseOrCancelToken(pts, cts);
public void Pause()
pts.IsPaused = true;
public void Cancel()
cts.Cancel();
public class PauseOrCancelToken
private PauseToken pt;
private CancellationToken ct;
public PauseOrCancelToken(PauseTokenSource pts, CancellationTokenSource cts)
this.pt = pts.Token;
this.ct = cts.Token;
public async Task PauseIfRequested()
await pt.WaitWhilePausedAsync();
public void CancelIfRequested()
ct.ThrowIfCancellationRequested();
Example
public class ProxyTester
public async static Task Start(List<Proxy> proxies, List<ProxyJudge> judges, PauseOrCancelToken pct, List<ProxyTest> tests = null)
if (tests == null)
tests = new List<ProxyTest>();
//Get external IP to check if proxy is anonymous.
var publicIp = await WebUtility.GetPublicIP();
//Validate proxy judges.
var tasks = new List<Task>();
foreach (var judge in judges)
tasks.Add(Task.Run(async () =>
judge.IsValid = await judge.TestValidityAsync();
await pct.PauseIfRequested();
pct.CancelIfRequested();
));
await Task.WhenAll(tasks);
var validJudges = from judge in judges
where judge.IsValid
select judge;
if (validJudges.Count() == 0)
throw new Exception("No valid judges loaded.");
//Validate proxy tests.
tasks.Clear();
foreach (var test in tests)
tasks.Add(Task.Run(async () =>
test.IsValid = await test.TestValidityAsync();
await pct.PauseIfRequested();
pct.CancelIfRequested();
));
await Task.WhenAll(tasks);
var validTests = from test in tests
where test.IsValid
select test;
//Test proxies with a random, valid proxy judge. If valid, test with all valid proxy tests.
tasks.Clear();
foreach (var proxy in proxies)
tasks.Add(Task.Run(async () =>
proxy.IsValid = await proxy.TestValidityAsync(validJudges.ElementAt(RandomUtility.GetRandomInt(0, validJudges.Count())));
await pct.PauseIfRequested();
pct.CancelIfRequested();
if (proxy.IsValid)
proxy.TestedSites.AddRange(validTests);
var childTasks = new List<Task>();
foreach (var test in validTests)
childTasks.Add(Task.Run(async () =>
proxy.TestedSites.ElementAt(proxy.TestedSites.IndexOf(test)).IsValid = await proxy.TestValidityAsync(test);
await pct.PauseIfRequested();
pct.CancelIfRequested();
));
await Task.WhenAll(childTasks);
));
await Task.WhenAll(tasks);
c# beginner asynchronous winforms task-parallel-library
Perhaps it would be more beneficial for you, if you include a real situation where this is used. There might a better approach, maybe usingManualResetEvent
. There are only minors stuff that I can spot in your current solution that are potential improvements.
â Denis
Apr 6 at 2:33
1
@Denis Hi, thanks for the response. I posted a simplified use case simply because it would add about 150 more LOC to this example, most of it unrelated to the implementations of PauseOrCancelToken and PauseOrCancelTokenSource. But if you really think it would help, I will edit my post in a bit.
â David Stampher
Apr 6 at 2:39
1
@Denis Ok, I edited my post and added what I intend to use this for in production. I left some unrelated classes out like Proxy and ProxyJudge, but if you need to see those too, let me know. I will probably end up creating a new method, PauseOrCancelIfRequested() to turn those 2 LOC into 1.
â David Stampher
Apr 6 at 3:27
add a comment |Â
up vote
4
down vote
favorite
up vote
4
down vote
favorite
I added this implementation of PauseToken and PauseTokenSource to my project from this MSDN blog post: Cooperatively pausing async methods
Since I will usually be passing in both a PauseToken and a CancellationToken into async methods, I am trying to encapsulate both of them into a single class, PauseOrCancelToken, created by PauseOrCancelTokenSource. I'm not entirely sure if I have implemented it correctly, although it does work as intended. Just wondering if I overlooked anything important that someone else might be able to spot.
public partial class PauseCancelForm : Form
private PauseOrCancelTokenSource pcts = new PauseOrCancelTokenSource();
public PauseCancelForm()
InitializeComponent();
private void StartButton_Click(object sender, EventArgs e)
Task.Run(() =>
DoSomeAsyncStuff(pcts.Token).Wait();
);
private async Task DoSomeAsyncStuff(PauseOrCancelToken pct)
var proxies = new List<Proxy>();
var judges = new List<ProxyJudge>();
for (int i = 0; i < 100; i++)
proxies.Add(new Proxy("127.0.0." + RandomUtility.GetRandomInt(1, 5), 8888));
judges.Add(new ProxyJudge("http://azenv.net"));
await ProxyTester.Start(proxies, judges, pct);
private void PauseButton_Click(object sender, EventArgs e)
pcts.Pause();
private void StopButton_Click(object sender, EventArgs e)
pcts.Cancel();
public class PauseOrCancelTokenSource
private PauseTokenSource pts = new PauseTokenSource();
private CancellationTokenSource cts = new CancellationTokenSource();
public PauseOrCancelToken Token get return new PauseOrCancelToken(pts, cts);
public void Pause()
pts.IsPaused = true;
public void Cancel()
cts.Cancel();
public class PauseOrCancelToken
private PauseToken pt;
private CancellationToken ct;
public PauseOrCancelToken(PauseTokenSource pts, CancellationTokenSource cts)
this.pt = pts.Token;
this.ct = cts.Token;
public async Task PauseIfRequested()
await pt.WaitWhilePausedAsync();
public void CancelIfRequested()
ct.ThrowIfCancellationRequested();
Example
public class ProxyTester
public async static Task Start(List<Proxy> proxies, List<ProxyJudge> judges, PauseOrCancelToken pct, List<ProxyTest> tests = null)
if (tests == null)
tests = new List<ProxyTest>();
//Get external IP to check if proxy is anonymous.
var publicIp = await WebUtility.GetPublicIP();
//Validate proxy judges.
var tasks = new List<Task>();
foreach (var judge in judges)
tasks.Add(Task.Run(async () =>
judge.IsValid = await judge.TestValidityAsync();
await pct.PauseIfRequested();
pct.CancelIfRequested();
));
await Task.WhenAll(tasks);
var validJudges = from judge in judges
where judge.IsValid
select judge;
if (validJudges.Count() == 0)
throw new Exception("No valid judges loaded.");
//Validate proxy tests.
tasks.Clear();
foreach (var test in tests)
tasks.Add(Task.Run(async () =>
test.IsValid = await test.TestValidityAsync();
await pct.PauseIfRequested();
pct.CancelIfRequested();
));
await Task.WhenAll(tasks);
var validTests = from test in tests
where test.IsValid
select test;
//Test proxies with a random, valid proxy judge. If valid, test with all valid proxy tests.
tasks.Clear();
foreach (var proxy in proxies)
tasks.Add(Task.Run(async () =>
proxy.IsValid = await proxy.TestValidityAsync(validJudges.ElementAt(RandomUtility.GetRandomInt(0, validJudges.Count())));
await pct.PauseIfRequested();
pct.CancelIfRequested();
if (proxy.IsValid)
proxy.TestedSites.AddRange(validTests);
var childTasks = new List<Task>();
foreach (var test in validTests)
childTasks.Add(Task.Run(async () =>
proxy.TestedSites.ElementAt(proxy.TestedSites.IndexOf(test)).IsValid = await proxy.TestValidityAsync(test);
await pct.PauseIfRequested();
pct.CancelIfRequested();
));
await Task.WhenAll(childTasks);
));
await Task.WhenAll(tasks);
c# beginner asynchronous winforms task-parallel-library
I added this implementation of PauseToken and PauseTokenSource to my project from this MSDN blog post: Cooperatively pausing async methods
Since I will usually be passing in both a PauseToken and a CancellationToken into async methods, I am trying to encapsulate both of them into a single class, PauseOrCancelToken, created by PauseOrCancelTokenSource. I'm not entirely sure if I have implemented it correctly, although it does work as intended. Just wondering if I overlooked anything important that someone else might be able to spot.
public partial class PauseCancelForm : Form
private PauseOrCancelTokenSource pcts = new PauseOrCancelTokenSource();
public PauseCancelForm()
InitializeComponent();
private void StartButton_Click(object sender, EventArgs e)
Task.Run(() =>
DoSomeAsyncStuff(pcts.Token).Wait();
);
private async Task DoSomeAsyncStuff(PauseOrCancelToken pct)
var proxies = new List<Proxy>();
var judges = new List<ProxyJudge>();
for (int i = 0; i < 100; i++)
proxies.Add(new Proxy("127.0.0." + RandomUtility.GetRandomInt(1, 5), 8888));
judges.Add(new ProxyJudge("http://azenv.net"));
await ProxyTester.Start(proxies, judges, pct);
private void PauseButton_Click(object sender, EventArgs e)
pcts.Pause();
private void StopButton_Click(object sender, EventArgs e)
pcts.Cancel();
public class PauseOrCancelTokenSource
private PauseTokenSource pts = new PauseTokenSource();
private CancellationTokenSource cts = new CancellationTokenSource();
public PauseOrCancelToken Token get return new PauseOrCancelToken(pts, cts);
public void Pause()
pts.IsPaused = true;
public void Cancel()
cts.Cancel();
public class PauseOrCancelToken
private PauseToken pt;
private CancellationToken ct;
public PauseOrCancelToken(PauseTokenSource pts, CancellationTokenSource cts)
this.pt = pts.Token;
this.ct = cts.Token;
public async Task PauseIfRequested()
await pt.WaitWhilePausedAsync();
public void CancelIfRequested()
ct.ThrowIfCancellationRequested();
Example
public class ProxyTester
public async static Task Start(List<Proxy> proxies, List<ProxyJudge> judges, PauseOrCancelToken pct, List<ProxyTest> tests = null)
if (tests == null)
tests = new List<ProxyTest>();
//Get external IP to check if proxy is anonymous.
var publicIp = await WebUtility.GetPublicIP();
//Validate proxy judges.
var tasks = new List<Task>();
foreach (var judge in judges)
tasks.Add(Task.Run(async () =>
judge.IsValid = await judge.TestValidityAsync();
await pct.PauseIfRequested();
pct.CancelIfRequested();
));
await Task.WhenAll(tasks);
var validJudges = from judge in judges
where judge.IsValid
select judge;
if (validJudges.Count() == 0)
throw new Exception("No valid judges loaded.");
//Validate proxy tests.
tasks.Clear();
foreach (var test in tests)
tasks.Add(Task.Run(async () =>
test.IsValid = await test.TestValidityAsync();
await pct.PauseIfRequested();
pct.CancelIfRequested();
));
await Task.WhenAll(tasks);
var validTests = from test in tests
where test.IsValid
select test;
//Test proxies with a random, valid proxy judge. If valid, test with all valid proxy tests.
tasks.Clear();
foreach (var proxy in proxies)
tasks.Add(Task.Run(async () =>
proxy.IsValid = await proxy.TestValidityAsync(validJudges.ElementAt(RandomUtility.GetRandomInt(0, validJudges.Count())));
await pct.PauseIfRequested();
pct.CancelIfRequested();
if (proxy.IsValid)
proxy.TestedSites.AddRange(validTests);
var childTasks = new List<Task>();
foreach (var test in validTests)
childTasks.Add(Task.Run(async () =>
proxy.TestedSites.ElementAt(proxy.TestedSites.IndexOf(test)).IsValid = await proxy.TestValidityAsync(test);
await pct.PauseIfRequested();
pct.CancelIfRequested();
));
await Task.WhenAll(childTasks);
));
await Task.WhenAll(tasks);
c# beginner asynchronous winforms task-parallel-library
edited Apr 6 at 6:06
t3chb0t
32k54195
32k54195
asked Apr 6 at 1:37
David Stampher
2509
2509
Perhaps it would be more beneficial for you, if you include a real situation where this is used. There might a better approach, maybe usingManualResetEvent
. There are only minors stuff that I can spot in your current solution that are potential improvements.
â Denis
Apr 6 at 2:33
1
@Denis Hi, thanks for the response. I posted a simplified use case simply because it would add about 150 more LOC to this example, most of it unrelated to the implementations of PauseOrCancelToken and PauseOrCancelTokenSource. But if you really think it would help, I will edit my post in a bit.
â David Stampher
Apr 6 at 2:39
1
@Denis Ok, I edited my post and added what I intend to use this for in production. I left some unrelated classes out like Proxy and ProxyJudge, but if you need to see those too, let me know. I will probably end up creating a new method, PauseOrCancelIfRequested() to turn those 2 LOC into 1.
â David Stampher
Apr 6 at 3:27
add a comment |Â
Perhaps it would be more beneficial for you, if you include a real situation where this is used. There might a better approach, maybe usingManualResetEvent
. There are only minors stuff that I can spot in your current solution that are potential improvements.
â Denis
Apr 6 at 2:33
1
@Denis Hi, thanks for the response. I posted a simplified use case simply because it would add about 150 more LOC to this example, most of it unrelated to the implementations of PauseOrCancelToken and PauseOrCancelTokenSource. But if you really think it would help, I will edit my post in a bit.
â David Stampher
Apr 6 at 2:39
1
@Denis Ok, I edited my post and added what I intend to use this for in production. I left some unrelated classes out like Proxy and ProxyJudge, but if you need to see those too, let me know. I will probably end up creating a new method, PauseOrCancelIfRequested() to turn those 2 LOC into 1.
â David Stampher
Apr 6 at 3:27
Perhaps it would be more beneficial for you, if you include a real situation where this is used. There might a better approach, maybe using
ManualResetEvent
. There are only minors stuff that I can spot in your current solution that are potential improvements.â Denis
Apr 6 at 2:33
Perhaps it would be more beneficial for you, if you include a real situation where this is used. There might a better approach, maybe using
ManualResetEvent
. There are only minors stuff that I can spot in your current solution that are potential improvements.â Denis
Apr 6 at 2:33
1
1
@Denis Hi, thanks for the response. I posted a simplified use case simply because it would add about 150 more LOC to this example, most of it unrelated to the implementations of PauseOrCancelToken and PauseOrCancelTokenSource. But if you really think it would help, I will edit my post in a bit.
â David Stampher
Apr 6 at 2:39
@Denis Hi, thanks for the response. I posted a simplified use case simply because it would add about 150 more LOC to this example, most of it unrelated to the implementations of PauseOrCancelToken and PauseOrCancelTokenSource. But if you really think it would help, I will edit my post in a bit.
â David Stampher
Apr 6 at 2:39
1
1
@Denis Ok, I edited my post and added what I intend to use this for in production. I left some unrelated classes out like Proxy and ProxyJudge, but if you need to see those too, let me know. I will probably end up creating a new method, PauseOrCancelIfRequested() to turn those 2 LOC into 1.
â David Stampher
Apr 6 at 3:27
@Denis Ok, I edited my post and added what I intend to use this for in production. I left some unrelated classes out like Proxy and ProxyJudge, but if you need to see those too, let me know. I will probably end up creating a new method, PauseOrCancelIfRequested() to turn those 2 LOC into 1.
â David Stampher
Apr 6 at 3:27
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
4
down vote
accepted
The only important thing, I can see is missing, is to let PauseOrCancelTokenSource
implement IDisposable
to make it possible to dispose the CancellationTokenSource
field properly. There are many opinions about the necessity to dispose CancellationTokens, but you should at least give the client the opportunity to do so. See this.
PauseOrCancelToken
should have a public CancellationToken CancellationToken => ct;
to make it possible to pass the cancellation token to async calls to external apis like await Task.Delay(1000, pct.CancellationToken);
so they can respond to a cancel request.
You could maybe combine PauseIfRequested()
and CancelIfRequested()
into one method, because you always call them both at the same time anyway.
My modification to your classes would be something like:
public class PauseOrCancelTokenSource : IDisposable
private PauseTokenSource pts = new PauseTokenSource();
private CancellationTokenSource cts = new CancellationTokenSource();
public PauseOrCancelToken Token get return new PauseOrCancelToken(pts, cts);
public void Pause()
pts.IsPaused = true;
public void Cancel()
cts.Cancel();
public bool IsDisposed => cts == null;
public void Dispose()
if (cts != null)
cts.Dispose();
cts = null;
public class PauseOrCancelToken
private PauseToken pt;
private CancellationToken ct;
public PauseOrCancelToken(PauseTokenSource pts, CancellationTokenSource cts)
this.pt = pts.Token;
this.ct = cts.Token;
public CancellationToken CancellationToken => ct;
public async Task PauseIfRequested()
await pt.WaitWhilePausedAsync();
public void CancelIfRequested()
ct.ThrowIfCancellationRequested();
public async Task PauseOrCancel()
ct.ThrowIfCancellationRequested();
await pt.WaitWhilePausedAsync();
Disclaimer: I haven't tested properly, so you should read it as only suggestions.
As @Denis mentioned, the pause part could be done really simple and easy with AsyncManualResetEvent
but the PauseToken/-Source seems to work just fine.
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
4
down vote
accepted
The only important thing, I can see is missing, is to let PauseOrCancelTokenSource
implement IDisposable
to make it possible to dispose the CancellationTokenSource
field properly. There are many opinions about the necessity to dispose CancellationTokens, but you should at least give the client the opportunity to do so. See this.
PauseOrCancelToken
should have a public CancellationToken CancellationToken => ct;
to make it possible to pass the cancellation token to async calls to external apis like await Task.Delay(1000, pct.CancellationToken);
so they can respond to a cancel request.
You could maybe combine PauseIfRequested()
and CancelIfRequested()
into one method, because you always call them both at the same time anyway.
My modification to your classes would be something like:
public class PauseOrCancelTokenSource : IDisposable
private PauseTokenSource pts = new PauseTokenSource();
private CancellationTokenSource cts = new CancellationTokenSource();
public PauseOrCancelToken Token get return new PauseOrCancelToken(pts, cts);
public void Pause()
pts.IsPaused = true;
public void Cancel()
cts.Cancel();
public bool IsDisposed => cts == null;
public void Dispose()
if (cts != null)
cts.Dispose();
cts = null;
public class PauseOrCancelToken
private PauseToken pt;
private CancellationToken ct;
public PauseOrCancelToken(PauseTokenSource pts, CancellationTokenSource cts)
this.pt = pts.Token;
this.ct = cts.Token;
public CancellationToken CancellationToken => ct;
public async Task PauseIfRequested()
await pt.WaitWhilePausedAsync();
public void CancelIfRequested()
ct.ThrowIfCancellationRequested();
public async Task PauseOrCancel()
ct.ThrowIfCancellationRequested();
await pt.WaitWhilePausedAsync();
Disclaimer: I haven't tested properly, so you should read it as only suggestions.
As @Denis mentioned, the pause part could be done really simple and easy with AsyncManualResetEvent
but the PauseToken/-Source seems to work just fine.
add a comment |Â
up vote
4
down vote
accepted
The only important thing, I can see is missing, is to let PauseOrCancelTokenSource
implement IDisposable
to make it possible to dispose the CancellationTokenSource
field properly. There are many opinions about the necessity to dispose CancellationTokens, but you should at least give the client the opportunity to do so. See this.
PauseOrCancelToken
should have a public CancellationToken CancellationToken => ct;
to make it possible to pass the cancellation token to async calls to external apis like await Task.Delay(1000, pct.CancellationToken);
so they can respond to a cancel request.
You could maybe combine PauseIfRequested()
and CancelIfRequested()
into one method, because you always call them both at the same time anyway.
My modification to your classes would be something like:
public class PauseOrCancelTokenSource : IDisposable
private PauseTokenSource pts = new PauseTokenSource();
private CancellationTokenSource cts = new CancellationTokenSource();
public PauseOrCancelToken Token get return new PauseOrCancelToken(pts, cts);
public void Pause()
pts.IsPaused = true;
public void Cancel()
cts.Cancel();
public bool IsDisposed => cts == null;
public void Dispose()
if (cts != null)
cts.Dispose();
cts = null;
public class PauseOrCancelToken
private PauseToken pt;
private CancellationToken ct;
public PauseOrCancelToken(PauseTokenSource pts, CancellationTokenSource cts)
this.pt = pts.Token;
this.ct = cts.Token;
public CancellationToken CancellationToken => ct;
public async Task PauseIfRequested()
await pt.WaitWhilePausedAsync();
public void CancelIfRequested()
ct.ThrowIfCancellationRequested();
public async Task PauseOrCancel()
ct.ThrowIfCancellationRequested();
await pt.WaitWhilePausedAsync();
Disclaimer: I haven't tested properly, so you should read it as only suggestions.
As @Denis mentioned, the pause part could be done really simple and easy with AsyncManualResetEvent
but the PauseToken/-Source seems to work just fine.
add a comment |Â
up vote
4
down vote
accepted
up vote
4
down vote
accepted
The only important thing, I can see is missing, is to let PauseOrCancelTokenSource
implement IDisposable
to make it possible to dispose the CancellationTokenSource
field properly. There are many opinions about the necessity to dispose CancellationTokens, but you should at least give the client the opportunity to do so. See this.
PauseOrCancelToken
should have a public CancellationToken CancellationToken => ct;
to make it possible to pass the cancellation token to async calls to external apis like await Task.Delay(1000, pct.CancellationToken);
so they can respond to a cancel request.
You could maybe combine PauseIfRequested()
and CancelIfRequested()
into one method, because you always call them both at the same time anyway.
My modification to your classes would be something like:
public class PauseOrCancelTokenSource : IDisposable
private PauseTokenSource pts = new PauseTokenSource();
private CancellationTokenSource cts = new CancellationTokenSource();
public PauseOrCancelToken Token get return new PauseOrCancelToken(pts, cts);
public void Pause()
pts.IsPaused = true;
public void Cancel()
cts.Cancel();
public bool IsDisposed => cts == null;
public void Dispose()
if (cts != null)
cts.Dispose();
cts = null;
public class PauseOrCancelToken
private PauseToken pt;
private CancellationToken ct;
public PauseOrCancelToken(PauseTokenSource pts, CancellationTokenSource cts)
this.pt = pts.Token;
this.ct = cts.Token;
public CancellationToken CancellationToken => ct;
public async Task PauseIfRequested()
await pt.WaitWhilePausedAsync();
public void CancelIfRequested()
ct.ThrowIfCancellationRequested();
public async Task PauseOrCancel()
ct.ThrowIfCancellationRequested();
await pt.WaitWhilePausedAsync();
Disclaimer: I haven't tested properly, so you should read it as only suggestions.
As @Denis mentioned, the pause part could be done really simple and easy with AsyncManualResetEvent
but the PauseToken/-Source seems to work just fine.
The only important thing, I can see is missing, is to let PauseOrCancelTokenSource
implement IDisposable
to make it possible to dispose the CancellationTokenSource
field properly. There are many opinions about the necessity to dispose CancellationTokens, but you should at least give the client the opportunity to do so. See this.
PauseOrCancelToken
should have a public CancellationToken CancellationToken => ct;
to make it possible to pass the cancellation token to async calls to external apis like await Task.Delay(1000, pct.CancellationToken);
so they can respond to a cancel request.
You could maybe combine PauseIfRequested()
and CancelIfRequested()
into one method, because you always call them both at the same time anyway.
My modification to your classes would be something like:
public class PauseOrCancelTokenSource : IDisposable
private PauseTokenSource pts = new PauseTokenSource();
private CancellationTokenSource cts = new CancellationTokenSource();
public PauseOrCancelToken Token get return new PauseOrCancelToken(pts, cts);
public void Pause()
pts.IsPaused = true;
public void Cancel()
cts.Cancel();
public bool IsDisposed => cts == null;
public void Dispose()
if (cts != null)
cts.Dispose();
cts = null;
public class PauseOrCancelToken
private PauseToken pt;
private CancellationToken ct;
public PauseOrCancelToken(PauseTokenSource pts, CancellationTokenSource cts)
this.pt = pts.Token;
this.ct = cts.Token;
public CancellationToken CancellationToken => ct;
public async Task PauseIfRequested()
await pt.WaitWhilePausedAsync();
public void CancelIfRequested()
ct.ThrowIfCancellationRequested();
public async Task PauseOrCancel()
ct.ThrowIfCancellationRequested();
await pt.WaitWhilePausedAsync();
Disclaimer: I haven't tested properly, so you should read it as only suggestions.
As @Denis mentioned, the pause part could be done really simple and easy with AsyncManualResetEvent
but the PauseToken/-Source seems to work just fine.
edited Apr 6 at 8:25
t3chb0t
32k54195
32k54195
answered Apr 6 at 7:47
Henrik Hansen
3,8931417
3,8931417
add a comment |Â
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f191371%2fpauseorcanceltokensource%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Perhaps it would be more beneficial for you, if you include a real situation where this is used. There might a better approach, maybe using
ManualResetEvent
. There are only minors stuff that I can spot in your current solution that are potential improvements.â Denis
Apr 6 at 2:33
1
@Denis Hi, thanks for the response. I posted a simplified use case simply because it would add about 150 more LOC to this example, most of it unrelated to the implementations of PauseOrCancelToken and PauseOrCancelTokenSource. But if you really think it would help, I will edit my post in a bit.
â David Stampher
Apr 6 at 2:39
1
@Denis Ok, I edited my post and added what I intend to use this for in production. I left some unrelated classes out like Proxy and ProxyJudge, but if you need to see those too, let me know. I will probably end up creating a new method, PauseOrCancelIfRequested() to turn those 2 LOC into 1.
â David Stampher
Apr 6 at 3:27