I am using ThreadPool in .NET to make some web request in the background, and I want to have a "Stop" button to cancel all the threads even if they are in the middle of making a request, so a simple bool wont do the job.
How can I do that?
Your situation is pretty much the canonical use-case for the Cancellation model in the .NET framework.
The idea is that you create a CancellationToken object and make it available to the operation that you might want to cancel. Your operation occasionally checks the token's IsCancellationRequested property, or calls ThrowIfCancellationRequested.
You can create a CancellationToken, and request cancellation through it, by using the CancellationTokenSource class.
This cancellation model integrates nicely with the .NET Task Parallel Library, and is pretty lightweight, more so than using system objects such as ManualResetEvent (though that is a perfectly valid solution too).
The correct way to handle this is to have a flag object that you signal.
The code running in those threads needs to check that flag periodically to see if it should exit.
For instance, a ManualResetEvent object is suitable for this.
You could then ask the threads to exit like this:
evt.Set();
and inside the threads you would check for it like this:
if (evt.WaitOne(0))
return; // or otherwise exit the thread
Secondly, since you're using the thread pool, what happens is that all the items you've queued up will still be processed, but if you add the if-statement above to the very start of the thread method, it will exit immediately. If that is not good enough you should build your own system using normal threads, that way you have complete control.
Oh, and just to make sure, do not use Thread.Abort. Ask the threads to exit nicely, do not outright kill them.
If you are going to stop/cancel something processing in another thread, ThreadPool is not the best choice, you should use Thread instead, and manage all of them in a container(e.g. a global List<Thread>), that guarantees you have full control of all the threads.
Related
I've been wondering is there any way in which we can move BackgroundWorker to sleep and resume it again just like thread. I've searched in many forums in vain. None of them show any method which would do that. I checked Microsoft documentation and found out there isn't any predefined methods.
I know the workarounds by using resetEvents. Just asking for any other possible and much easier way.
If you use Task instead of BackgroundWorker you can use the PauseTokenSource.
This class is similar to the built in CancellationTokenSource only suitable for pausing tasks and not canceling them.
PauseTokenSource API was built exactly for what you need and it's API can replace your usage of Thread.Sleep and all the signaling events.
Other option besides PauseTokenSource can use AsyncManualResetEvent, the mechanism internal is quite similar but they differ in the API. I think that PauseTokenSource is much more convenient and especially built for this purpose, more info here.
From within your DoWork handler, you can call Thread.Sleep() whenever you want. If you want, from the GUI, to be able to signal the worker to pause, set up a concurrent queue, feed your sleep requests into it from the GUI thread, and have your DoWork handler check the queue periodically, pausing as requested.
(If you want to pause the BackgroundWorker until signaled again rather than for a certain period of time, you can do that in a similar way--just periodically check the queue for a "restart" command and sleep a few milliseconds before checking again.)
I read here:
.NET async, can a single thread time-slice between tasks?
that, unless you explicitly use async/await, tasks will not "time-slice" on the same thread in the backend thread-pool. Is this guaranteed? Or merely a side effect of the current implementation of the TPL?
If not guaranteed, it would cause problems with using lock():
Consider two Tasks which access a method that locks on a full SerialPort transaction (send a message and receive, or timeout) before releasing. If time-slicing occurs on the same thread and the SerialPort access is slow enough, the lock would fail to do its job (letting both calls through, because they are technically on the same thread).
Yes, as long as you don't do anything that makes (some parts of) your code execute on another thread (await, Task.Run(), Task.ContinueWith(), Thread, …), then it's safe to use lock or another thread-based synchronization mechanism.
One possible exception is if you have a custom TaskScheduler (e.g. TaskScheduler.FromCurrentSynchronizationContext()) and you somehow make that scheduler try to execute more Tasks while your Task is still executing (e.g. something like Application.DoEvents()). In that case, your Task still won't move to another thread, but it may be paused while another Task executes on the same thread. But this situation should be exceedingly rare.
How to cancel an asynchronous call? The .NET APM doesn't seem to support this operation.
I have the following loop in my code which spawns multiple threads on the ThreadPool. When I click a button on my UI, I would like these threads (or asynchronous calls) to end.
foreach (var sku in skus)
{
loadSku.BeginInvoke(...
}
Is there any elegant solution other than creating a global "Cancel flag" and having the asynchronous methods to look for it?
A "cancel flag" is the way to do it, though not a global one, necessarily. The unavoidable point is that you need some way to signal to the thread that it should stop what it's doing.
In the case of BeginInvoke, this is hard to do with anything but a global flag, because the work is carried out on the threadpool, and you don't know which thread. You have a couple of options (in order of preference):
Use the BackgroundWorker instead of BeginInvoke. This has cancellation functionality baked-in. This has other benefits, like progress monitoring, and "Work complete" callbacks. It also nicely handles exceptions.
Use ThreadPool.QueueUserWorkItem, passing in an object as the state that has a Cancel() method that sets a Cancelled flag that the executing code can check. Of course you'll need to keep a reference to the state object so you can call Cancel() on it (which is something the BackgroundWorker does for you - you have a component on your form. (Thanks to Fredrik for reminding about this).
Create your own ThreadStart delegate, passing in a state object as with option 2.
If you're lookin for a "TerminateAsnyc" method, you won't find one. Therefore, no, there's probably no elegant way while using Control.BeginInvoke/EndInvoke. Thus, I'd put the boolean flag on the UI thread and have the delegate being executed asynchronously check that flag periodically while it's executing.
However, you might check into using background worker threads.
There are definitely other solutions, although I don't know that I would call them "elegant".
you could call Abort or Interrupt on the thread but these can have some negative side effects. Personally, for something like this I prefer to use BackgroundWorker if possible. It has a Cancel feature but it is similar to what you mentioned - a bool flag in the class that you have to periodically check for in the executing code (at least it's not a global flag). This post on stopping threads in .NET is a bit old but goes over some of the pitfalls of the other options I mentioned above.
I want to implement a timeout on the execution of tasks in a project that uses the CCR. Basically when I post an item to a Port or enqueue a Task to a DispatcherQueue I want to be able to abort the task or the thread that its running on if it takes longer than some configured time. How can I do this?
Can you confirm what you are asking? Are you running a long-lived task in the Dispatcher? Killing the thread would break the CCR model, so you need to be able to signal to the thread to finish its work and yield. Assuming it's a loop that is not finishing quick enough, you might choose to enqueue a timer:
var resultTimeoutPort = new Port<DateTime>();
dispatcherQueue.EnqueueTimer(TimeSpan.FromSeconds(RESULT_TIMEOUT),
resultTimeoutPort);
and ensure the blocking thread has available a reference to resultTimeoutPort. In the blocking loop, one of the exit conditions might be:
do
{
//foomungus amount of work
}while(resultTimeoutPort.Test()==null&&
someOtherCondition)
Please post more info if I'm barking up the wrong tree.
You could register the thread (Thread.CurrentThread) at the beginning of your CCR "Receive" handler (or in a method that calls your method via a delegate). Then you can do your periodic check and abort if necessary basically the same way you would have done it if you created the thread manually. The catch is that if you use your own Microsoft.Ccr.Core.Dispatcher with a fixed number of threads, I don't think there is a way to get those threads back once you abort them (based on my testing). So, if your dispatcher has 5 threads, you'll only be able to abort 5 times before posting will no longer work regardless of what tasks have been registered. However, if you construct a DispatcherQueue using the CLR thread pool, any CCR threads you abort will be replaced automatically and you won't have that problem. From what I've seen, although the CCR dispatcher is recommended, I think using the CLR thread pool is the way to go in this situation.
How do you design a method/class that should support cancellation of the operation?
I realized that I never do that in a consistent manner and I want to change that.
Some of the things I have used:
a boolean property on the class IsCancelled that I synchronize internally. sometimes I have a CanCancel property if the operation cannot be canceled at any given time
pass a Func< bool > delegate that I repeatedly call to see if the operation has been canceled.
terminate the thread manually - although this is definitely bad practise
How do you normally do that?
I would go for the CancellationTokenSource and using its associated CancellationToken
as a means for signalling cancellation. This is new in .Net Framework v4.
The concept is that the CancellationTokenSource simply calls Cancel and your code can share CancellationTokens on which you regular inspect the IsCancellationRequested property in it. This should especially be the case in tight loops or longer running operations, so as to allow your code to stop in a timely fashion.
The added bonus is that even blocked threads blocked due to a wait on a SemaphoreSlim, ManualResetEventSlim can be signalled to gracefully exit, since these classes accept a CancellationToken in their Wait method in .Net Framework v4
For example have a look at: ManualResetEventSlim.Wait that has overloads accepting a CancellationToken.
I'd prefer to use the IsCancelled property idea. Your background thread method can check it at the appropriate times, do any cleanup as needed, and terminate the operation. If you're using a callback method when the thread finishes, it's easy to check the property and see if it's valid or not. I've used framework worker thread classes that used this strategy in the past, and it's worked well.
Go back to the use case: what is the behavior you're trying to provide? If you have an asynchronous operation that you want to cancel, then you probably can best implement a method that lets you notify the other threadt via a flag or a semaphore. Sending a signal is a nice method to get it's attention, although I haven't looked into C#'s handling of signals. If you need to be able to cancel and undo, the Command pattern comes in handy.