PauseOrCancelTokenSource

The name of the pictureThe name of the pictureThe name of the pictureClash 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);









share|improve this question





















  • 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

















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);









share|improve this question





















  • 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













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);









share|improve this question













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);











share|improve this question












share|improve this question




share|improve this question








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 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

















  • 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
















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











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.






share|improve this answer























    Your Answer




    StackExchange.ifUsing("editor", function ()
    return StackExchange.using("mathjaxEditing", function ()
    StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
    StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
    );
    );
    , "mathjax-editing");

    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "196"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    convertImagesToLinks: false,
    noModals: false,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );








     

    draft saved


    draft discarded


















    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






























    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.






    share|improve this answer



























      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.






      share|improve this answer

























        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.






        share|improve this answer















        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.







        share|improve this answer















        share|improve this answer



        share|improve this answer








        edited Apr 6 at 8:25









        t3chb0t

        32k54195




        32k54195











        answered Apr 6 at 7:47









        Henrik Hansen

        3,8931417




        3,8931417






















             

            draft saved


            draft discarded


























             


            draft saved


            draft discarded














            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













































































            Popular posts from this blog

            Chat program with C++ and SFML

            Function to Return a JSON Like Objects Using VBA Collections and Arrays

            Will my employers contract hold up in court?