Wait for timer or event, whichever happens soonest - c#

I have what is currently a single-threaded console app which does something every 30s... e.g.
while(exitFlagNotSet)
{
doStuff();
Thread.Sleep(30000);
}
However I'd also like to listen for application-exit a bit along the lines of Capture console exit C#. In such a situation I can't wait 30s - my app will be forcibly terminated after 5s IIRC.
So is there a way to refactor my approach so the 30s wait may be aborted when something occurs? I've done this kind of thing in C++ but don't know what the terminology and techniques are in C#/.net

You can use WaitHandle of CancellationToken to do that:
static void Main(string[] args) {
var cts = new CancellationTokenSource();
var token = cts.Token;
EventHandler handler = new EventHandler(sig => {
// may want to investigate signal here
// cancel if appropriate
cts.Cancel();
return true;
});
// this is from your linked answer
SetConsoleCtrlHandler(handler, true);
while (!cts.IsCancellationRequested) {
Console.WriteLine("doing stuff");
var cancelled = token.WaitHandle.WaitOne(30000);
if (cancelled) {
// handle exit
Console.WriteLine("Cancelled!");
break;
}
}
}
When calncelled - WaitHandle of CancellationToken will be signalled, and as such WaitOne returns true. If WaitOne exited because of timeout - it returns false.

Related

Is there a way to allow thread to safely exit without doing thread.Abort?

How do I allow the current thread to safely exit and perform a delete action to some resources of the thread?
I used Thread.Abort() but using that it seems that it does not release the resources. I am finding a way to allow the thread to safely exit and as soon as it exits, I want to perform the delete action.
I am writing it using C#, if any one has any examples or suggestions please contribute.
var tokenSource2 = new CancellationTokenSource();
CancellationToken ct = tokenSource2.Token;
var task = Task.Run(() => dssPut_Command("Compile " + SystemID + "abc.dss"), tokenSource2.Token);
if (!task.Wait(TimeSpan.FromSeconds(2)))
{
ct.ThrowIfCancellationRequested();
bool moreToDo = true;
while (moreToDo)
{
// Poll on this property if you have to do
// other cleanup before throwing.
if (ct.IsCancellationRequested)
{
// Clean up here, then...
ct.ThrowIfCancellationRequested();
}
tokenSource2.Cancel();
}
}
The best way to go about this depends on your scenario, but one of my preferred ways is usually to use a CancellationToken to signal that the thread should exit gracefully.
This avoids using Thread.Abort() (which is generally not a good idea), and it allows your worker to decide when it is appropriate to cancel and it can perform any necessary clean-up.
In the code you've posted, the method that calls Task.Run() should only create the CancellationTokenSource, pass the CancellationToken into the dssPut_Command method, and set cts.CancelAfter() to set the timeout. Then, only the code inside the method dssPut_Command should be checking if cancellation is requested.
static void Main()
{
using (var cts = new CancellationTokenSource())
{
// Start the worker thread and pass the
// CancellationToken to it
Console.WriteLine("MAIN: Starting worker thread");
var worker = Task.Run(() => dssPut_Command(cts.Token));
// Make the token cancel automatically after 3 seconds
cts.CancelAfter(3000);
// Wait for worker thread to exit
Console.WriteLine("MAIN: Waiting for the worker to exit");
worker.Wait();
Console.WriteLine("MAIN: Main thread exiting after worker exited");
}
}
static void dssPut_Command(object tokenObj)
{
Console.WriteLine("WORKER: Worker thread started");
var cancellationToken = (CancellationToken)tokenObj;
// You can check if cancellation has been requested
if (cancellationToken.IsCancellationRequested)
{
// If there's no need to clean up, you can just return
return;
}
try
{
// Or you can throw an OperationCanceledException automatically
cancellationToken.ThrowIfCancellationRequested();
// Pass the CancellationToken to any methods you call
// so they can throw OperationCanceledException when
// the token is canceled.
DoWork(cancellationToken);
}
catch (OperationCanceledException)
{
// Do any clean-up work, if necessary
Console.WriteLine("WORKER: Worker exiting gracefully");
}
}
static void DoWork(CancellationToken cancellationToken)
{
// Simulating a long running operation
Task.Delay(TimeSpan.FromMinutes(1), cancellationToken).GetAwaiter().GetResult();
}

Is there a way to abort a thread and then open it again with a new variable?

I want to open a thread to do the things it needs to do until a new command is given by the user. Then this thread should either close or receive a new command.
I have seen many posts that sending a variable to a running thread is hard, that is why I decided to kill the thread and start it again with the new variable.
I used the following post: https://stackoverflow.com/a/1327377 but without success. When I start the thread again (after it has done abort()) it gives me an exception: System.Threading.ThreadStateException.
private static Thread t = new Thread(Threading);
private static bool _running = false;
static void Main(string[] args)
{
[get arg]
if (CanRedo(arg))
{
if (t.IsAlive)
{
_running = false;
t.Interrupt();
if (t.Join(2000)) // with a '!' like in the post, abort() would not be called
{
t.Abort();
}
}
_running = true;
t.Start(arg); // gives System.Threading.ThreadStateException
}
}
private static void Threading(object obj)
{
_stopped = false;
string arg = obj.ToString();
while(_running)
{
if (bot._isDone)
{
ExecuteInstruction(arg);
}
}
}
What am I doing wrong?
I'm going to guess that you don't literally mean to abort the thread and start that same thread again. That's because if we start a thread to do some work we don't care which thread it is. If you cancel one thing and start something else, you probably don't care if it's the same thread or a different one. (In fact it's probably better if you don't care. If you need precise control over which thread is doing what then something has gotten complicated.) You can't "abort" a thread and restart it anyway.
Regarding Thread.Abort:
The Thread.Abort method should be used with caution. Particularly when you call it to abort a thread other than the current thread, you do not know what code has executed or failed to execute when the ThreadAbortException is thrown, nor can you be certain of the state of your application or any application and user state that it is responsible for preserving. For example, calling Thread.Abort may prevent static constructors from executing or prevent the release of unmanaged resources.
It's like firing an employee by teleporting them out of the building without warning. What if they were in the middle of a phone call or carrying a stack of papers? That might be okay in an emergency, but it wouldn't be a normal way to operate. It would be better to let the employee know that they need to wrap up what they're doing immediately. Put down what you're carrying. Tell the customer that you can't finish entering their order and they'll need to call back.
You're describing an expected behavior, so it would be better to cancel the thread in an orderly way.
That's where we might use a CancellationToken. In effect you're passing an object to the thread and telling it to check it from time to time to see if it should cancel what it's doing.
So you could start your thread like this:
class Program
{
static void Main(string[] args)
{
using (var cts = new CancellationTokenSource())
{
ThreadPool.QueueUserWorkItem(DoSomethingOnAnotherThread, cts.Token);
// This is just for demonstration. It allows the other thread to run for a little while
// before it gets canceled.
Thread.Sleep(5000);
cts.Cancel();
}
}
private static void DoSomethingOnAnotherThread(object obj)
{
var cancellationToken = (CancellationToken) obj;
// This thread does its thing. Once in a while it does this:
if (cancellationToken.IsCancellationRequested)
{
return;
}
// Keep doing what it's doing.
}
}
Whatever the method is that's running in your separate thread, it's going to check IsCancellationRequested from time to time. If it's right in the middle of doing something it can stop. If it has unmanaged resources it can dispose them. But the important thing is that you can cancel what it does in a predictable way that leaves your application in a known state.
CancellationToken is one way to do this. In other really simple scenarios where the whole thing is happening inside one class you could also use a boolean field or property that acts as a flag to tell the thread if it needs to stop. The separate thread checks it to see if cancellation has been requested.
But using the CancellationToken makes it more manageable if you want to refactor and now the method executing on another thread is a in separate class. When you use a known pattern it makes it easier for the next person to understand what's going on.
Here's some documentation.
What about doing it this way:
private static Task t = null;
private static CancellationTokenSource cts = null;
static void Main(string[] args)
{
[get arg]
if (CanRedo(out var arg))
{
if (t != null)
{
cts.Cancel();
t.Wait();
}
// Set up a new task and matching cancellation token
cts = new CancellationTokenSource();
t = Task.Run(() => liveTask(arg, cts.Token));
}
}
private static void liveTask(object obj, CancellationToken ct)
{
string arg = obj.ToString();
while(!ct.IsCancellationRequested)
{
if (bot._isDone)
{
ExecuteInstruction(arg);
}
}
}
Tasks are cancellable, and I can see nothing in your thread that requires the same physical thread to be re-used.

Cancel Tasks in c# [duplicate]

We could abort a Thread like this:
Thread thread = new Thread(SomeMethod);
.
.
.
thread.Abort();
But can I abort a Task (in .Net 4.0) in the same way not by cancellation mechanism. I want to kill the Task immediately.
The guidance on not using a thread abort is controversial. I think there is still a place for it but in exceptional circumstance. However you should always attempt to design around it and see it as a last resort.
Example;
You have a simple windows form application that connects to a blocking synchronous web service. Within which it executes a function on the web service within a Parallel loop.
CancellationTokenSource cts = new CancellationTokenSource();
ParallelOptions po = new ParallelOptions();
po.CancellationToken = cts.Token;
po.MaxDegreeOfParallelism = System.Environment.ProcessorCount;
Parallel.ForEach(iListOfItems, po, (item, loopState) =>
{
Thread.Sleep(120000); // pretend web service call
});
Say in this example, the blocking call takes 2 mins to complete. Now I set my MaxDegreeOfParallelism to say ProcessorCount. iListOfItems has 1000 items within it to process.
The user clicks the process button and the loop commences, we have 'up-to' 20 threads executing against 1000 items in the iListOfItems collection. Each iteration executes on its own thread. Each thread will utilise a foreground thread when created by Parallel.ForEach. This means regardless of the main application shutdown, the app domain will be kept alive until all threads have finished.
However the user needs to close the application for some reason, say they close the form.
These 20 threads will continue to execute until all 1000 items are processed. This is not ideal in this scenario, as the application will not exit as the user expects and will continue to run behind the scenes, as can be seen by taking a look in task manger.
Say the user tries to rebuild the app again (VS 2010), it reports the exe is locked, then they would have to go into task manager to kill it or just wait until all 1000 items are processed.
I would not blame you for saying, but of course! I should be cancelling these threads using the CancellationTokenSource object and calling Cancel ... but there are some problems with this as of .net 4.0. Firstly this is still never going to result in a thread abort which would offer up an abort exception followed by thread termination, so the app domain will instead need to wait for the threads to finish normally, and this means waiting for the last blocking call, which would be the very last running iteration (thread) that ultimately gets to call po.CancellationToken.ThrowIfCancellationRequested.
In the example this would mean the app domain could still stay alive for up to 2 mins, even though the form has been closed and cancel called.
Note that Calling Cancel on CancellationTokenSource does not throw an exception on the processing thread(s), which would indeed act to interrupt the blocking call similar to a thread abort and stop the execution. An exception is cached ready for when all the other threads (concurrent iterations) eventually finish and return, the exception is thrown in the initiating thread (where the loop is declared).
I chose not to use the Cancel option on a CancellationTokenSource object. This is wasteful and arguably violates the well known anti-patten of controlling the flow of the code by Exceptions.
Instead, it is arguably 'better' to implement a simple thread safe property i.e. Bool stopExecuting. Then within the loop, check the value of stopExecuting and if the value is set to true by the external influence, we can take an alternate path to close down gracefully. Since we should not call cancel, this precludes checking CancellationTokenSource.IsCancellationRequested which would otherwise be another option.
Something like the following if condition would be appropriate within the loop;
if (loopState.ShouldExitCurrentIteration || loopState.IsExceptional || stopExecuting) {loopState.Stop(); return;}
The iteration will now exit in a 'controlled' manner as well as terminating further iterations, but as I said, this does little for our issue of having to wait on the long running and blocking call(s) that are made within each iteration (parallel loop thread), since these have to complete before each thread can get to the option of checking if it should stop.
In summary, as the user closes the form, the 20 threads will be signaled to stop via stopExecuting, but they will only stop when they have finished executing their long running function call.
We can't do anything about the fact that the application domain will always stay alive and only be released when all foreground threads have completed. And this means there will be a delay associated with waiting for any blocking calls made within the loop to complete.
Only a true thread abort can interrupt the blocking call, and you must mitigate leaving the system in a unstable/undefined state the best you can in the aborted thread's exception handler which goes without question. Whether that's appropriate is a matter for the programmer to decide, based on what resource handles they chose to maintain and how easy it is to close them in a thread's finally block. You could register with a token to terminate on cancel as a semi workaround i.e.
CancellationTokenSource cts = new CancellationTokenSource();
ParallelOptions po = new ParallelOptions();
po.CancellationToken = cts.Token;
po.MaxDegreeOfParallelism = System.Environment.ProcessorCount;
Parallel.ForEach(iListOfItems, po, (item, loopState) =>
{
using (cts.Token.Register(Thread.CurrentThread.Abort))
{
Try
{
Thread.Sleep(120000); // pretend web service call
}
Catch(ThreadAbortException ex)
{
// log etc.
}
Finally
{
// clean up here
}
}
});
but this will still result in an exception in the declaring thread.
All things considered, interrupt blocking calls using the parallel.loop constructs could have been a method on the options, avoiding the use of more obscure parts of the library. But why there is no option to cancel and avoid throwing an exception in the declaring method strikes me as a possible oversight.
But can I abort a Task (in .Net 4.0) in the same way not by
cancellation mechanism. I want to kill the Task immediately.
Other answerers have told you not to do it. But yes, you can do it. You can supply Thread.Abort() as the delegate to be called by the Task's cancellation mechanism. Here is how you could configure this:
class HardAborter
{
public bool WasAborted { get; private set; }
private CancellationTokenSource Canceller { get; set; }
private Task<object> Worker { get; set; }
public void Start(Func<object> DoFunc)
{
WasAborted = false;
// start a task with a means to do a hard abort (unsafe!)
Canceller = new CancellationTokenSource();
Worker = Task.Factory.StartNew(() =>
{
try
{
// specify this thread's Abort() as the cancel delegate
using (Canceller.Token.Register(Thread.CurrentThread.Abort))
{
return DoFunc();
}
}
catch (ThreadAbortException)
{
WasAborted = true;
return false;
}
}, Canceller.Token);
}
public void Abort()
{
Canceller.Cancel();
}
}
disclaimer: don't do this.
Here is an example of what not to do:
var doNotDoThis = new HardAborter();
// start a thread writing to the console
doNotDoThis.Start(() =>
{
while (true)
{
Thread.Sleep(100);
Console.Write(".");
}
return null;
});
// wait a second to see some output and show the WasAborted value as false
Thread.Sleep(1000);
Console.WriteLine("WasAborted: " + doNotDoThis.WasAborted);
// wait another second, abort, and print the time
Thread.Sleep(1000);
doNotDoThis.Abort();
Console.WriteLine("Abort triggered at " + DateTime.Now);
// wait until the abort finishes and print the time
while (!doNotDoThis.WasAborted) { Thread.CurrentThread.Join(0); }
Console.WriteLine("WasAborted: " + doNotDoThis.WasAborted + " at " + DateTime.Now);
Console.ReadKey();
You shouldn't use Thread.Abort()
Tasks can be Cancelled but not aborted.
The Thread.Abort() method is (severely) deprecated.
Both Threads and Tasks should cooperate when being stopped, otherwise you run the risk of leaving the system in a unstable/undefined state.
If you do need to run a Process and kill it from the outside, the only safe option is to run it in a separate AppDomain.
This answer is about .net 3.5 and earlier.
Thread-abort handling has been improved since then, a.o. by changing the way finally blocks work.
But Thread.Abort is still a suspect solution that you should always try to avoid.
And in .net Core (.net 5+) Thread.Abort() will now throw a PlatformNotSupportedException .
Kind of underscoring the 'deprecated' point.
Everyone knows (hopefully) its bad to terminate thread. The problem is when you don't own a piece of code you're calling. If this code is running in some do/while infinite loop , itself calling some native functions, etc. you're basically stuck. When this happens in your own code termination, stop or Dispose call, it's kinda ok to start shooting the bad guys (so you don't become a bad guy yourself).
So, for what it's worth, I've written those two blocking functions that use their own native thread, not a thread from the pool or some thread created by the CLR. They will stop the thread if a timeout occurs:
// returns true if the call went to completion successfully, false otherwise
public static bool RunWithAbort(this Action action, int milliseconds) => RunWithAbort(action, new TimeSpan(0, 0, 0, 0, milliseconds));
public static bool RunWithAbort(this Action action, TimeSpan delay)
{
if (action == null)
throw new ArgumentNullException(nameof(action));
var source = new CancellationTokenSource(delay);
var success = false;
var handle = IntPtr.Zero;
var fn = new Action(() =>
{
using (source.Token.Register(() => TerminateThread(handle, 0)))
{
action();
success = true;
}
});
handle = CreateThread(IntPtr.Zero, IntPtr.Zero, fn, IntPtr.Zero, 0, out var id);
WaitForSingleObject(handle, 100 + (int)delay.TotalMilliseconds);
CloseHandle(handle);
return success;
}
// returns what's the function should return if the call went to completion successfully, default(T) otherwise
public static T RunWithAbort<T>(this Func<T> func, int milliseconds) => RunWithAbort(func, new TimeSpan(0, 0, 0, 0, milliseconds));
public static T RunWithAbort<T>(this Func<T> func, TimeSpan delay)
{
if (func == null)
throw new ArgumentNullException(nameof(func));
var source = new CancellationTokenSource(delay);
var item = default(T);
var handle = IntPtr.Zero;
var fn = new Action(() =>
{
using (source.Token.Register(() => TerminateThread(handle, 0)))
{
item = func();
}
});
handle = CreateThread(IntPtr.Zero, IntPtr.Zero, fn, IntPtr.Zero, 0, out var id);
WaitForSingleObject(handle, 100 + (int)delay.TotalMilliseconds);
CloseHandle(handle);
return item;
}
[DllImport("kernel32")]
private static extern bool TerminateThread(IntPtr hThread, int dwExitCode);
[DllImport("kernel32")]
private static extern IntPtr CreateThread(IntPtr lpThreadAttributes, IntPtr dwStackSize, Delegate lpStartAddress, IntPtr lpParameter, int dwCreationFlags, out int lpThreadId);
[DllImport("kernel32")]
private static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32")]
private static extern int WaitForSingleObject(IntPtr hHandle, int dwMilliseconds);
While it's possible to abort a thread, in practice it's almost always a very bad idea to do so. Aborthing a thread means the thread is not given a chance to clean up after itself, leaving resources undeleted, and things in unknown states.
In practice, if you abort a thread, you should only do so in conjunction with killing the process. Sadly, all too many people think ThreadAbort is a viable way of stopping something and continuing on, it's not.
Since Tasks run as threads, you can call ThreadAbort on them, but as with generic threads you almost never want to do this, except as a last resort.
I faced a similar problem with Excel's Application.Workbooks.
If the application is busy, the method hangs eternally. My approach was simply to try to get it in a task and wait, if it takes too long, I just leave the task be and go away (there is no harm "in this case", Excel will unfreeze the moment the user finishes whatever is busy).
In this case, it's impossible to use a cancellation token. The advantage is that I don't need excessive code, aborting threads, etc.
public static List<Workbook> GetAllOpenWorkbooks()
{
//gets all open Excel applications
List<Application> applications = GetAllOpenApplications();
//this is what we want to get from the third party library that may freeze
List<Workbook> books = null;
//as Excel may freeze here due to being busy, we try to get the workbooks asynchronously
Task task = Task.Run(() =>
{
try
{
books = applications
.SelectMany(app => app.Workbooks.OfType<Workbook>()).ToList();
}
catch { }
});
//wait for task completion
task.Wait(5000);
return books; //handle outside if books is null
}
This is my implementation of an idea presented by #Simon-Mourier, using the dotnet thread, short and simple code:
public static bool RunWithAbort(this Action action, int milliseconds)
{
if (action == null) throw new ArgumentNullException(nameof(action));
var success = false;
var thread = new Thread(() =>
{
action();
success = true;
});
thread.IsBackground = true;
thread.Start();
thread.Join(milliseconds);
thread.Abort();
return success;
}
You can "abort" a task by running it on a thread you control and aborting that thread. This causes the task to complete in a faulted state with a ThreadAbortException. You can control thread creation with a custom task scheduler, as described in this answer. Note that the caveat about aborting a thread applies.
(If you don't ensure the task is created on its own thread, aborting it would abort either a thread-pool thread or the thread initiating the task, neither of which you typically want to do.)
using System;
using System.Threading;
using System.Threading.Tasks;
...
var cts = new CancellationTokenSource();
var task = Task.Run(() => { while (true) { } });
Parallel.Invoke(() =>
{
task.Wait(cts.Token);
}, () =>
{
Thread.Sleep(1000);
cts.Cancel();
});
This is a simple snippet to abort a never-ending task with CancellationTokenSource.

C#: CancellationToken doesn't cancel blocking method

.NET 4.5.1: It appears, I can't cancel a blocking method running inside a task using the CancellationTokenSource built-in timeout.
class Program
{
static void Main(string[] args)
{
var cts = new System.Threading.CancellationTokenSource();
System.Console.CancelKeyPress += (s, e) =>
{
e.Cancel = true;
cts.Cancel();
};
MainAsync(args, cts.Token).Wait();
}
// MainAsync from http://stackoverflow.com/questions/9208921/async-on-main-method-of-console-app
static async Task MainAsync(string[] args, System.Threading.CancellationToken token)
{
Console.WriteLine("Starting MainAsync");
var cts = new System.Threading.CancellationTokenSource(3000);
var task = Task.Factory.StartNew(() =>
{
Console.WriteLine("Starting task...");
var t = new System.Net.Sockets.TcpClient();
var buffer = new byte[t.ReceiveBufferSize];
t.Connect(new System.Net.IPEndPoint(System.Net.IPAddress.Parse("127.0.0.1"), 1337));
Console.WriteLine("Recieving...");
t.Client.Receive(buffer);
Console.WriteLine("Finished Recieving...");
return true;
}, cts.Token);
var success = await task;
Console.WriteLine("Did the task complete succesfuly?", success);
}
}
The output from the above Short, Self Contained, Correct Example (I hope it's correct) is:
Starting MainAsync
Starting task...
Recieving...
Why does the task doesn't cancel, no exception is thrown?
As I state on my blog, "You keep using that CancellationToken there. I do not think it means what you think it means."
In particular, the CancellationToken passed to StartNew will only cancel the starting of the delegate. If you want the delegate itself to support cancellation, then the delegate itself will have to observe the CancellationToken.
I am not sure but I guess you are confusing "requesting a cancellation" with "terminating or aborting a thread/task".
These are two completly different things. According to the description about the Canellation in Managerd Threads the provided functionality enables you to send something like a signal, indicating, that the operation in progress shall be stopped.
How and if you react on that signal is - as a programmer - up to you.
In your example you've started a new task
var task = Task.Factory.StartNew(() =>
{
Console.WriteLine("Starting task...");
var t = new System.Net.Sockets.TcpClient();
var buffer = new byte[t.ReceiveBufferSize];
t.Connect(new System.Net.IPEndPoint(System.Net.IPAddress.Parse("127.0.0.1"), 1337));
Console.WriteLine("Recieving...");
t.Client.Receive(buffer);
Console.WriteLine("Finished Recieving...");
return true;
}, cts.Token);
which does not handle the cancellation nor is it suitable to do so.
Canellation would be used e.g. if you want to break out of a loop with many iterations - therefore you would check in each iteration whether the CancellationToken.IsCancellationRequested has been set to true or not.
If so, you can react accordingly.
What you want is to abort the thread that's behind the current task which is in my opinion only possible by creating a new instance of the Thread class for yourself and handle the abort accordingly.

How do I cancel a concurrent heavy Task?

I have a Task by heavy process runs in that's body. In addition, we have no access to the body of this method (heavy process) and we must wait until to completion the process.
Now my question is, how do I cancel without interrupting the task so that I do not check any value in it?
My codes like this:
private CancellationTokenSource CTS = new CancellationTokenSource();
public void CallMyMethod(CancellationTokenSource cts)
{
//
// Several methods they call each other. And pass tokens to each other.
MyProcess(cts);
}
private void MyProcess(CancellationTokenSource cts)
{
CancellationToken token = cts.Token;
Task.Run(() =>
{
token.ThrowIfCancellationRequested(); // Work just when ThrowIfCancellationRequested called. and check that again
if (token.IsCancellationRequested) // Must be checked every time, and after the investigation not work.
return;
// My long time process
HeavyProcess(); // We have no access to the body of this method
}, token);
}
private void CancelProcess()
{
try
{
//
// I want to cancel Now, Just Now not after HeavyProcess completion or checking token again!
//
CTS.Cancel();
CTS.Token.ThrowIfCancellationRequested();
}
catch
{ }
}
Can I cancel the heavy process after that running ?
If you can't control the long running method, then cooperative cancellation isn't going to work. What you can do is offload the heavy job to a different process, and monitor on the process in a background thread:
private void MyProcess(CancellationTokenSource cts)
{
cts.Token.ThrowIfCancellationRequested();
// Move the heavy work to a different process
var process = Process.Start(new ProcessStartInfo { /* */ });
// Register to the cancellation, where if the process is still
// running, kill it.
cts.Token.Register(() =>
{
if (!process.HasExited)
{
process.Kill();
}
});
}
And now, when you cancel, you invoke the callback where we terminate the process:
private void CancelProcess()
{
CTS.Cancel();
}

Categories

Resources