How can I implement a method with abort ability?
Imagine I have a grid, when data loads the grid starts calculating the totals and show them on another grid beneath itself. I want to start calculating totals right after loading data.
I tried using threads but a problem rose up:
When I click on Load button two rapid times, for the first time the thread starts working and the second time I get an error saying the thread is busy.
I need to implement some method that can be aborted and started again.
For this I would indeed use threads. Depending on your .NET framework you can start by setting up an IProgress object which can be used to provides UI updates from a background thread-pool thread. So firstly you could create
IProgress<object> progressIndicator =
new Progress<object>(ReportProgress);
where ReportProgress is some method
public void ReportProgress(object o) { /* Update UI components here on the Main UI thread */ }
Now, to start the work and provide cancellation support, you can do some thing like
CancellationTokenSource source = new CancellationTokenSource();
CancellationToken token = source.Token;
Task task = Task.Factory.StartNew(() =>
{
// Do your work here and provide cancellation support.
for (int i = 0; i < someMaxValue; ++i)
{
// Update the UI if required.
progressIndicator.ReportProgress(someObject);
// No check for you cancellation condition...
if (source != null && someCancelCondition)
source.Cancel(); // This will throw a CancellationException().
}
}, token,
TaskCreationOptions.None,
TaskScheduler.Default)
.ContinueWith(ant =>
{
// Here you must handle you exceptions and trap your cancellation.
});
For more information see J. Albahari's Threading tutorial.
I hope this helps.
When load is clicked, create a CancellationTokenSource and store it. Pass in its CancellationToken to your worker thread, and check it regularly in your calculations so you can abort in a timely manner.
When Load is clicked again, you can abort the current thread by calling Cancel() on your TokenSource.
Related
I'm really new to threading multitasking/multithreading, but I'm working on a project where I think I need it. The user will be editing a fairly complex diagram, and I want the program to check for validity of the diagram. The validity check is non-trivial (polynomial time, though, not NP - seconds, not minutes or years, but I don't want to hold the user up for a few seconds after every change) so I would like the program to check for validity in the background and highlight inconsistencies when it finds them. When the user makes certain changes to the diagram (changes the structure, not just the labels on elements), the validation will have to throw away what it was doing and start again. I'm assuming the user will eventually take a break to think/go for a pee/go for a coffee/chat to that rather cute person two cubicles along, but in case they don't, I have to let the validation run to completion in some circumstances (before a save or a printout, for example). Broad-brush, what are the features of C# I'll need to learn, and how do I structure that?
Broad Brush. Here we go.
Q: "What are the features of C# I'll need to learn?"
A: You can get by nicely with a basic toolkit consisting (roughly speaking) of:
System.Threading.Tasks.Task
System.Threading.CancellationTokenSource
System.Threading.SemaphoreSlim
Q: "I don't want to hold the user up for a few seconds after every change"
A: OK, so we will never-ever block the UI thread. Fire off a Task to run a background validation routine that checks every now and then to see if it's been cancelled.
CancellationTokenSource _cts = null;
SemaphoreSlim ssBusy = new SemaphoreSlim(2);
private void ExecValidityCheck()
{
ssBusy.Wait();
Task.Run(() =>
{
try
{
_cts = new CancellationTokenSource();
LongRunningValidation(_cts.Token);
}
finally
{
ssBusy.Release();
}
})
.GetAwaiter()
.OnCompleted(CheckForRestart);
}
We'll call CheckForRestart using GetAwaiter().OnCompleted(). This just means that without blocking we'll be notified as a callback when the thread finishes for one of three reasons:
Cancelled
Cancelled, but with an intent to start the validation over from the beginning.
Ran validation to completion
By calling CheckForRestart we determine whether to start it over again or not.
void CheckForRestart()
{
BeginInvoke((MethodInvoker)delegate
{
if (_restart)
{
_restart = false;
ExecValidityCheck();
}
else
{
buttonCancel.Enabled = false;
}
});
}
Rather that post the complete code here, I pushed a simple working example to our GitHub. You can browse it there or clone and run it. 20-second screen capture. When the RESTART button is clicked in the video, it's checking the CurrentCount property of the Semaphore. In a threadsafe way it determines whether the validation routine is already running or not.
I hope I've managed to give you a few ideas about where to start. Sure, the explanation I've given here has a few holes but feel free to address your critical concerns in the comments and I'll try to respond.
You probably need to learn about asynchronous programming with async/await, and about cooperative cancellation. The standard practice for communicating cancellation is by throwing an OperationCanceledException. Methods that are intended to be cancelable accept a CancellationToken as argument, and observe frequently the IsCancellationRequested method of the token. So here is the basic structure of a cancelable Validate method with a boolean result:
bool Validate(CancellationToken token)
{
for (int i = 0; i < 50; i++)
{
// Throw an OperationCanceledException if cancellation is requested
token.ThrowIfCancellationRequested();
Thread.Sleep(100); // Simulate some CPU-bound work
}
return true;
}
The "driver" of the CancellationToken is a class named CancellationTokenSource. In your case you'll have to create multiple instances of this class, one for every time that the diagram is changed. You must store them somewhere so that you can call later their Cancel method, so lets make two private fields inside the Form, one for the most recent CancellationTokenSource, and one for the most recent validation Task:
private Task<bool> _validateTask;
private CancellationTokenSource _validateCTS;
Finally you'll have to write the logic for the event handler of the Diagram_Changed event. It is probably not desirable to have multiple validation tasks running side by side, so it's a good idea to await for the completion of the previous task before launching a new one. It is important that awaiting a task doesn't block the UI. This introduces the complexity that multiple Diagram_Changed events, along with other unrelated events, can occur before the completion of the code inside the handler. Fortunately you can count on the single-threaded nature of the UI, and not have to worry about the thread-safety of accessing the _validateTask and _validateCTS fields by multiple asynchronous workflows. You do need to be aware though that after every await these fields may hold different values than before the await.
private async void Diagram_Changed(object sender, EventArgs e)
{
bool validationResult;
using (var cts = new CancellationTokenSource())
{
_validateCTS?.Cancel(); // Cancel the existing CancellationTokenSource
_validateCTS = cts; // Publish the new CancellationTokenSource
if (_validateTask != null)
{
// Await the completion of the previous task before spawning a new one
try { await _validateTask; }
catch { } // Ignore any exception
}
if (cts != _validateCTS) return; // Preempted (the event was fired again)
// Run the Validate method in a background thread
var task = Task.Run(() => Validate(cts.Token), cts.Token);
_validateTask = task; // Publish the new task
try
{
validationResult = await task; // Await the completion of the task
}
catch (OperationCanceledException)
{
return; // Preempted (the validation was canceled)
}
finally
{
// Cleanup before disposing the CancellationTokenSource
if (_validateTask == task) _validateTask = null;
if (_validateCTS == cts) _validateCTS = null;
}
}
// Do something here with the result of the validation
}
The Validate method should not include any UI manipulation code, because it will be running in a background thread. Any effects to the UI should occur after the completion of the method, through the returned result of the validation task.
I have an Authorizer object which may be accessed from multiple concurrent worker threads. If the user has recently logged in, it can return an access token immediately. However it has to dispatch to the UI thread to show a login brower window to the user whenever they need to login again. While the login method is waiting for the user to log in, other worker threads may request authorization, and it needs to block those until the user is done logging in. However, since the external call may also have involved the UI thread, blocking external calls also prevents forward progress for the login process, because the UI thread is blocked in the re-entrance.
I can't just use locks (which are re-entrant-per-thread) because dispatching to the UI thread (required for UI element interaction) decouples the relationship between threads and the operation being performed (the thread may change in the process of doing a single "logical" operation, versus many operations all must make use of the same UI thread at times).
Another way of looking at my problem is every time I call Dispatcher.Invoke from the Authorizer to run the UI thread, I have a chance of it being "the wrong" operation that the dispatcher runs (or is running already) before the UI thread loops around to the operation the Authorizer login process needs. I can't let these other accesses proceed until login is complete, but I can't have my UI thread back until they do complete.
One solution would be to have the "block" actually run the dispatcher queue while it blocks. Is there anything like this existing already? If I have to write it from scratch, what is the best way to ask the framework to run other dispatcher tasks while I wait? Should I just do "while (blocked) { dispatcher.Invoke(() => {/nothing/}); }"?
You need to handle all of this asynchronously, rather than synchronously, as is so often the case in desktop UI programming.
Your Authorizer should not block until it can compute the result and return that result, it should instead return a Task<AuthorizationInformation> that will allow the caller to be notified of when the result is ready. The caller of the method, which may or may not be on the UI thread, the needs to add a continuation to that task and then yield up its call chain (to the message loop if it's the UI thread) so as to allow the Authorizer to do its thing, and then continue executing through the continuation applied to the task.
The authorize method could look something like this:
public class Authorizer
{
private static Lazy<Task<AuthorizationInformation>> tcsFactory;
static Authorizer()
{
tcsFactory = new Lazy<Task<AuthorizationInformation>>(
() =>
{
var tcs = new TaskCompletionSource<AuthorizationInformation>();
Dispatcher dispatcher = GetDispatcher();
dispatcher.BeginInvoke(new Action(() =>
{
var login = new LoginWindow();
login.ShowDialog();
var info = login.LoginInfo;
if (info != null)
tcs.TrySetResult(info);
else
tcs.TrySetException(new Exception("Failed to log in."));
}));
return tcs.Task;
});
}
public static Task<AuthorizationInformation> Authorize()
{
return tcsFactory.Value;
}
private static Dispatcher GetDispatcher()
{
throw new NotImplementedException();
}
}
The Lazy type is also highly useful for the thread safe "compute this value no more than once, have everyone that requests it be given that value, but don't begin computing it until at least one person asks for it. This allows us to lazily wait to start computing the value, then when we're ready to start computing it we create a TaskCompletionSource to generate a task that we can complete whenever we have a value. We can then asynchronously requests some work to be done in the UI thread, and then set the result of the task when it finishes.
Before you flag my question as being a duplicate, hear me out.
Most people have a long running non-UI operation that they are doing and need to unblock the UI thread. I have a long running UI operation which must run on the UI thread which is blocking the rest of my application. Basically, I am dynamically constructing DependencyObjects at run time and adding them to a UI component on my WPF application. The number of DependencyObjects that need to be created depends upon user input, of which there is no limit. One of the test inputs I have has about 6000 DependencyObjects that need to be created and loading them takes a couple minutes.
The usual solution of using a background worker in this case does not work, because once the DependencyObjects are created by the background worker, they can no longer be added to the UI component since they were created on the background thread.
My current attempt at a solution is to run the loop in a background thread, dispatch to the UI thread for each unit of work and then calling Thread.Yield() to give the UI thread a chance to update. This almost works - the UI thread does get the chance to update itself a couple times during the operation, but the application is still essentially blocked.
How can I get my application to keep updating the UI and processing events on other forms during this long running operation?
EDIT:
As requested, an example of my current 'solution':
private void InitializeForm(List<NonDependencyObject> myCollection)
{
Action<NonDependencyObject> doWork = (nonDepObj) =>
{
var dependencyObject = CreateDependencyObject(nonDepObj);
UiComponent.Add(dependencyObject);
// Set up some binding on each dependencyObject and update progress bar
...
};
Action background = () =>
{
foreach (var nonDependencyObject in myCollection)
{
if (nonDependencyObject.NeedsToBeAdded())
{
Dispatcher.Invoke(doWork, nonDependencyObject);
Thread.Yield(); //Doesn't give UI enough time to update
}
}
};
background.BeginInvoke(background.EndInvoke, null);
}
Changing Thread.Yield() to Thread.Sleep(1) seems to work, but is that really a good solution?
Sometimes it is indeed required to do the background work on the UI thread, particularly, when the majority of work is to deal with the user input.
Example: real-time syntax highlighting, as-you-type. It might be possible to offload some sub-work-items of such background operation to a pool thread, but that wouldn't eliminate the fact the text of the editor control is changing upon every new typed character.
Help at hand: await Dispatcher.Yield(DispatcherPriority.ApplicationIdle). This will give the user input events (mouse and keyboard) the best priority on the WPF Dispatcher event loop. The background work process may look like this:
async Task DoUIThreadWorkAsync(CancellationToken token)
{
var i = 0;
while (true)
{
token.ThrowIfCancellationRequested();
await Dispatcher.Yield(DispatcherPriority.ApplicationIdle);
// do the UI-related work
this.TextBlock.Text = "iteration " + i++;
}
}
This will keep the UI responsive and will do the background work as fast as possible, but with the idle priority.
We may want to enhance it with some throttle (wait for at least 100 ms between iterations) and better cancellation logic:
async Task DoUIThreadWorkAsync(CancellationToken token)
{
Func<Task> idleYield = async () =>
await Dispatcher.Yield(DispatcherPriority.ApplicationIdle);
var cancellationTcs = new TaskCompletionSource<bool>();
using (token.Register(() =>
cancellationTcs.SetCanceled(), useSynchronizationContext: true))
{
var i = 0;
while (true)
{
await Task.Delay(100, token);
await Task.WhenAny(idleYield(), cancellationTcs.Task);
token.ThrowIfCancellationRequested();
// do the UI-related work
this.TextBlock.Text = "iteration " + i++;
}
}
}
Updated as the OP has posted a sample code.
Based upon the code you posted, I agree with #HighCore's comment about the proper ViewModel.
The way you're doing it currently, background.BeginInvoke starts a background operation on a pool thread, then synchronously calls back the UI thread on a tight foreach loop, with Dispatcher.Invoke. This only adds an extra overhead. Besides, you're not observing the end of this operation, because you're simply ignoring the IAsyncResult returned by background.BeginInvoke. Thus, InitializeForm returns, while background.BeginInvoke continues on a background thread. Essentially, this is a fire-and-forget call.
If you really want to stick to the UI thread, below is how it can be done using the approach I described.
Note that _initializeTask = background() is still an asynchronous operation, despite it's taking place on the UI thread. You won't be able to make it synchronous without a nested Dispatcher event loop inside InitializeForm (which would be a really bad idea because of the implications with the UI re-entrancy).
That said, a simplified version (no throttle or cancellation) may look like this:
Task _initializeTask;
private void InitializeForm(List<NonDependencyObject> myCollection)
{
Action<NonDependencyObject> doWork = (nonDepObj) =>
{
var dependencyObject = CreateDependencyObject(nonDepObj);
UiComponent.Add(dependencyObject);
// Set up some binding on each dependencyObject and update progress bar
...
};
Func<Task> background = async () =>
{
foreach (var nonDependencyObject in myCollection)
{
if (nonDependencyObject.NeedsToBeAdded())
{
doWork(nonDependencyObject);
await Dispatcher.Yield(DispatcherPriority.ApplicationIdle);
}
}
};
_initializeTask = background();
}
It's often the case when I need to get a task done within X amount of seconds and if it doesn't complete, I want to keep going, processing the rest of the tasks
I've been defaulting to something like this:
Thread worker = new Thread(() => {
// do some long operation
});
Thread monitor = new Thread(() => {
Thread.Sleep(10000);
if(worker != null && worker.IsAlive) {
worker.Abort();
worker = null;
}
StartNextTask();
});
monitor.Start ();
worker.Start();
This works, but it is cumbersome because it uses two threads (yes, you can use the Task class as well to use threads from the threadpool).
AutoResetEvents and event based models don't quite work because the former blocks the monitor thread until the worker is done, and the event driven approach relies on the client to call the event and notify the monitor.
Are there alternative patterns to this that can follow the same semantics?
If you use the Task class as you say, you can also use Task.Wait() which does exactly what you want. Specify an amount of seconds to wait. The task doesn't get cancelled unless you cancel it by use of a CancellationToken
See: http://msdn.microsoft.com/en-us/library/dd235606.aspx
Saw this in some code but didn't make sense to me, So I was wondering if even it is a correct way of utilizing backgreound worker?
it is used like this on Form_Load event:
BackgroundWorker asyncWorker = new BackgroundWorker();
asyncWorker.DoWork += new DoWorkEventHandler(AsynchDoWork);
asyncWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(AsynchCompleted);
asyncWorker.RunWorkerAsync();
// a for each loop that can take some time to populate a combobx on the form
Also, is there a better alternative on achieving the same goal? other than backgroundworker?
I would use the Task Parralell Library for this. A good into tutorial is Task Parallel Library: 1 of n. To update a combo box following the result of some background task you could do something like this
// Get UI scheduler. Use this to update ui thread in continuation.
TaskScheduler uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
// You can use TPL like this...
List<object> objList = new List<object>();
Task<object[]> task = Task.Factory.StartNew<object[]>(() =>
{
// Pull all your data into some object.
object[] objArr = new object[] { "Some", "Stuff", "..." };
return objArr;
}, TaskCreationOptions.PreferFairness);
// Continuation firs after the antecedent task is completed.
task.ContinueWith(ant =>
{
// Get returned data set.
object[] resultSet = (task.Result as object[]);
// Check task status.
switch (task.Status)
{
// Handle any exceptions to prevent UnobservedTaskException.
case TaskStatus.RanToCompletion:
if (task.Result != null)
{
// Update UI comboBox.
}
break;
default:
break;
}
}, CancellationToken.None, TaskContinuationOptions.None, uiScheduler);
Here the uiScheduler lets you update the ui thread from within the continuation delegate which fires when the antecedent task completes (either successfully or otherwise).
The continuation also acts as an exception handler in this case to catch any AggregateExceptions they may be thrown from the background thread.
I hope this helps.
If I understand correctly, what you are actually asking is if you should fill the values in your Combobox from a background thread or from the UI thread.
If the reason it takes a long time to populate the Combobox is because it takes a long time to actually retrieve the items - for example, if you are retrieving them from a database, then you probably should do this work in a BackgroundWorker, and then only add the retrieved items to the Combobox on the RunWorkerCompleted event.
The RunWorkerCompleted event, while still running from a background thread, automatically calls Invoke under the hood for all access to UI elements, and therefore has no problem updating UI elements.
Of course, the long running lop has to be run inside the DoWork event, and not in the same code block as the call to RunWorkerAsync, as in your code example.
Conversely, if we are simply talking about a very large amount of readily available items, and the call to AddRange simply takes a lot of time because of the amount, you can not call this from a background thread, as winforms control can only be accessed from the UI thread.
I'm not sure about the scope, I would create the BackgroundWorker as a member of the class.
The BackgroundWorker takes the work off of the UI thread and has methods that provide easy access to update progress.
As for alternatives, it depends on what exactly your goals are. If it is a small task that doesn't update the UI, then the System.Threading.ThreadPool is an option.
To answer the question "Also, is there a better alternative on achieving the same goal? other than backgroundworker?".
No. This is the easiest way to handle long running blocking tasks for winforms. There are other methods (BeginInvoke), but it is much easier to just use background worker.