0

I have library that can run for up to 30 minutes or even more.

In my client code i want to have opportunity to stop working of library's instance; Hot can i do it?

For example

 public class TickMe { public void Run() { int i = 0; while (true) { Thread.Sleep(1000); Console.WriteLine("tik" + i); i++; } } } 

And client code:

public class Client { protected TickMe instance; public void Run() { TickMe instance = new TickMe(); instance.Run(); } public void Kill() { instance????? } } 

So what code i need to put in method Kill() to stop working instance of class TickMe ?

11
  • Your Run() method currently blocks the thread. Convert it to an async method, replace` Thread.Sleep()` with await Task.Delay() and learn how to use a CancellationToken that you'd pass to the Run() method and cancel it using the client. Commented Sep 23, 2021 at 13:30
  • You need some mechanism to stop the while-loop. Commented Sep 23, 2021 at 13:30
  • 3
    Ideally, work with the library authors so that they add support for cooperative cancellation via CancellationToken. The alternatively, when you yank the rug out from under the library when it has no idea that could happen can lead to... tricky to diagnose issues later. The library could be doing practically anything, including stuff that it only intends to temporarily change and you stop it being able to revert those changes Commented Sep 23, 2021 at 13:30
  • Thank u guys, i know about cancelation token and about that tasks. But loop can take like 10 minutes each. Even if i put "token.IsCancellationRequested" in end of my loop - i have to wait 10 minutes anyway. But i want immediate stop solution. Commented Sep 23, 2021 at 13:37
  • Can you make changes to TickMe.Run at all? If not theres basically nothing you can do to stop it running. Also your Client.Run method has a local variable instance which is completely separate from your class-level variable making it inaccessible outside that method (But im guessing this is a typo) Commented Sep 23, 2021 at 13:38

2 Answers 2

2

You need something that doesn't block the current thread and to exit the while-loop.

You could try something like this:

public class TickMe { private CancellationTokenSource _cancellationTokenSource; public async Task Start() { _cancellationTokenSource = new CancellationTokenSource(); int i = 0; while (!_cancellationTokenSource.IsCancellationRequested) { await Task.Delay(1000, _cancellationTokenSource.Token); Console.WriteLine("tik" + i); i++; } _cancellationTokenSource = null; } public void Stop() { _cancellationTokenSource?.Cancel(); } } public class Client { protected TickMe _instance; public async Task Run() { _instance = new TickMe(); await _instance.Start(); } public void Kill() { _instance.Stop(); } } 
Sign up to request clarification or add additional context in comments.

5 Comments

Even better: Pass the token in from the calling client - it may itself have received one rather than create one internally
@Jamiec If the client has a CancellationToken, I'd rather advise to use a CreateLinkedTokenSource to link them, so the TickMe can be cancelled without cancelling the Client, but still able to have a cascade effect on stopping the client and tickme directly. (so the comment "Pass the token in from the calling client" still stands with a little modification)
Looks nice! But anyway, if my loop takes like 10 minutes, i have to wait it. But i want to stop it when i request it.
@ssrdop You could move the while-loop to a Task.Run(() => ....), or just not await the _ = Run();
Yeah it only was example. In real i have library that have loop. Sure i can edit that library to add some tokens, but the problem is i want to stop it immediatly. Thank u for the answer!
2

First of all, let's make your tick asyncronous, to not block the current thread:

 public class TickMe { private int _counter; private object locker = new object(); public async Task Run(CancellationToken cancelationToken) { _counter = 0; while (!cancelationToken.IsCancellationRequested) { await Task.Delay(200); Console.WriteLine("tik" + _counter); lock (locker) { _counter++; } } } } 
  • Note the use of CancellationToken to stop the execution.
  • Note the use of lock to deal with the counter.

Then we create a CancellationToken to stop the execution of your asyncronous method, and pass it as parameter for the function on the main method and it's ready to go

 public class Program { public static async Task Main(string[] args) { CancellationTokenSource source = new CancellationTokenSource(); var cancelationToken = source.Token; var tick = new TickMe(); Task.Run(async () => await tick.Run(cancelationToken)); await Task.Delay(1000); await Task.Delay(1000); Console.WriteLine("foo"); await Task.Delay(1000); source.Cancel(); await Task.Delay(1000); await Task.Delay(1000); Console.WriteLine("bar"); } } 

The results should be closer to this:

tik0 tik1 tik2 tik3 tik4 tik5 tik6 tik7 tik8 foo tik9 tik10 tik11 tik12 tik13 bar 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.