I read somewhere that using Thread.Abort() method is one of the worst way to kill a thread because it does not free the memory assigned to this thread. (I don't know if that's true, correct me if it's wrong and Abort() method is the one I should use.) Therefore the best way to call killing a thread would be creating a variable that defiles if thread can run, ie:
bool threadResult;
t = new System.Threading.Thread(() => doSomeStuff());
t.Start();
abortThread();
//***************************************************
bool threadCanRun = true;
void doSomeStuff()
{
while(threadCanRun)
// do work
}
void abortThread()
{
threadCanRun = false;
}
But... what if the thread cannot be stopped like that? Ie:
void doSomeStuff()
{
WebClient wc = new Webclient();
string url = "www.mywebsite.com";
string content = wc.DownloadString(url);
}
Let's say that I want to spend less than 100ms on doing this thread^. If it won't end until the time passes (I'm using the following construction: if (t.Join(100)) ) I should abort it somehow to keep my program running. So, what's the proper way to end up the working thread?
Sure, in this particular case I can use try-catch to handle most of exceptions, but this is just an example. Also, if my connection is really slow and the webpage is really big it would take more that 100ms and no exception will be thrown.
PS. I'm almost sure that it does not matter, but I'm working on WPF app with some Forms references. The target FW is NET 4.0.
If you want your thread to be able to end in 100ms, you should design thread to check for running condition (threadCanRun) at least once per 100ms. Your question is too general so I cannot give you more precise answer.
Also, it is good programming practice to join with your thread immediately after threadCanRun = false; although somebody could disagree with that.
In my opinion using the BackgroundWorker class is safer but if you want to use a Thread then you have to implement a flag cancellation pattern.
If you are using .Net Framework 4.0 the you can use the CancellationTokenSource class like this:
public partial class Form1 : Form
{
CancellationTokenSource cancelSource = new CancellationTokenSource();
int threadCounter = 0;
int mainCounter = 0;
public void doSomeStuff(CancellationToken cancelToken)
{
cancelToken.ThrowIfCancellationRequested();
for (int i = 0; i < 100; i++)
{
threadCounter = i;
// If you want to cancel the thread just call the Cancel method of the cancelSource.
if (i == 88)
{
cancelSource.Cancel();
}
if (cancelSource.IsCancellationRequested)
{
// Do some Thread clean up here
}
}
}
private void button1_Click(object sender, EventArgs e)
{
new Thread(() => doSomeStuff(cancelSource.Token)).Start();
// Do something else while the thread has not been cancelled
while (!cancelSource.IsCancellationRequested)
{
mainCounter++;
}
textBox1.Text = "The thread was cancelled when 'mainCounter' was at: " + mainCounter.ToString();
}
}
Also you can use the CancellationToken which has the IsCancellationRequested property and ThrowIfCancellationRequested method.
Related
i know the common ways of cancelling a backgroundworker using eventwaithandles...
but i wanna know is that right to use a while loop to trap and pause working of a backgroundworker ? i coded like this :
Bool stop = false;
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
progressBar1.Minimum = 0;
progressBar1.Maximum = 100000;
progressBar1.Value = 0;
for (int i = 0; i < 100000; i++)
{
progressBar1.Value++;
if (i == 50000)
stop = true;
while (stop)
{ }
}
}
private void button1_Click(object sender, EventArgs e)
{
stop = !stop;
}
Did you try it? What happened? Was it what you wanted to happen? Did you notice your computer's fans speeding up, to handle all the heat from your CPU in a tight, "do-nothing" loop?
Fact is, you should not "pause" a background task in the first place; if you don't it to keep running, interrupt it. If you want to be able to resume later, provide a mechanism to allow that. Even having your thread blocked efficiently waiting on a WaitHandle object would be the wrong thing to do, because it wastes a thread pool thread.
The code you've posted here is about the worst way to implement "pausing". Instead of waiting on some synchronization object such as a WaitHandle, you have the current thread just loop without interrupting, constantly checking the value of a flag. Even ignoring the question of whether you're using volatile (the code example doesn't show that, but then it also wouldn't compile, so…), it's terrible to force a CPU core to do so much work and yet get nowhere.
Don't pause your BackgroundWorker.DoWork handler in the first place. Really. Just don't do that. But if you insist, then at least use some kind of waitable object instead of a "spin-wait" loop as in the example you've posted here.
Here's an example of how your code might work if you wanted to avoid altogether tying up a thread while "paused". First, don't use BackgroundWorker, because it doesn't have a graceful way to do this. Second, do use await…that does specifically what you want: it allows the current method to return, but without losing track of its progress. The method will resume executing when the thing it waited on indicates completion.
In the example below, I've tried to guess at what the code that calls RunWorkerAsync() looks like. Or rather, I just assumed you've got a button2, which when clicked you call that method to start your worker task. If this is not enough to get you pointed in the right direction, please improve your question by including a good, minimal, complete code example showing what you're actually doing.
// These fields will work together to provide a way for the thread to interrupt
// itself temporarily without actually using a thread at all.
private TaskCompletionSource<object> _pause;
private readonly object _pauseLock = new object();
private void button2_Click(object sender, DoWorkEventArgs e)
{
// Initialize ProgressBar. Note: in your version of the code, this was
// done in the DoWork event handler, but that handler isn't executed in
// the UI thread, and so accessing a UI object like progressBar1 is not
// a good idea. If you got away with it, you were lucky.
progressBar1.Minimum = 0;
progressBar1.Maximum = 100000;
progressBar1.Value = 0;
// This object will perform the duty of the BackgroundWorker's
// ProgressChanged event and ReportProgress() method.
Progress<int> progress = new Progress<int>(i => progressBar1.Value++);
// We do want the code to run in the background. Use Task.Run() to accomplish that
Task.Run(async () =>
{
for (int i = 0; i < 100000; i++)
{
progress.Report(i);
Task task = null;
// Locking ensures that the two threads which may be interacting
// with the _pause object do not interfere with each other.
lock (_pauseLock)
{
if (i == 50000)
{
// We want to pause. But it's possible we lost the race with
// the user, who also just pressed the pause button. So
// only allocate a new TCS if there isn't already one
if (_pause == null)
{
_pause = new TaskCompletionSource<object>();
}
}
// If by the time we get here, there's a TCS to wait on, then
// set our local variable for the Task to wait on. In this way
// we resolve any other race that might occur between the time
// we checked the _pause object and then later tried to wait on it
if (_pause != null)
{
task = _pause.Task;
}
}
if (task != null)
{
// This is the most important part: using "await" tells the method to
// return, but in a way that will allow execution to resume later.
// That is, when the TCS's Task transitions to the completed state,
// this method will resume executing, using any available thread
// in the thread pool.
await task;
// Once we resume execution here, reset the TCS, to allow the pause
// to go back to pausing again.
lock (_pauseLock)
{
_pause.Dispose();
_pause = null;
}
}
}
});
}
private void button1_Click(object sender, EventArgs e)
{
lock (_pauseLock)
{
// A bit more complicated than toggling a flag, granted. But it achieves
// the desirable goal.
if (_pause == null)
{
// Creates the object to wait on. The worker thread will look for
// this and wait if it exists.
_pause = new TaskCompletionSource<object>();
}
else if (!_pause.Task.IsCompleted)
{
// Giving the TCS a result causes its corresponding Task to transition
// to the completed state, releasing any code that might be waiting
// on it.
_pause.SetResult(null);
}
}
}
Note that the above is just as contrived as your original example. If all you had really was a simple single loop variable iterating from 0 to 100,000 and stopping halfway through, nothing nearly so complicated as the above would be required. You'd just store the loop variable in a data structure somewhere, exit the running task thread, and then when you want to resume, pass in the current loop variable value so the method can resume at the right index.
But I'm assuming your real-world example is not so simple. And the above strategy will work for any stateful processing, with the compiler doing all the heavy-lifting of storing away intermediate state for you.
I'm working with some code, that has an approach I've never dealt with before, and am hoping someone might be able to provide a spark of knowledge:
Effectively the class is setup like this:
void Loop()
{
for (int i = 0; i < 100; i++)
{
//need to block calls to this until UpdateComplete is hit
Update(i);
}
}
void Update(int i)
{
//asynchronous - returns immediately
}
void UpdateComplete()//called from another thread
{
//unblock further calls to Update();
}
The big caveat is that it's not possible to call Update() before UpdateComplete() has 'returned' or been calledback.
Ignoring any UI side effects, is there a neat solution to this problem?
I've currently got two strategies - one hacky and one I feel is over-complicated:
1 - Hacky: Set a global class boolean IsBlocked, that Update() sets to true and UpdateComplete() sets to false, and inside my for loop (in Loop()), just put in a while (IsBlocked){}.
2 - Over-complicated: Get rid of the loop altogether. Call Update(0); from inside Loop() instead, and have UpdateComplete() call Update(1);, Update(2); and so on.
I guess I'm hoping for something like a Thread.Pause that can then be remotely 'resumed' by another thread (the separate one that calls UpdateComplete()
Any ideas appreciated!
Async/await can also be used here
TaskCompletionSource<object> tcs = null;
async void Loop()
{
for (int i = 0; i < 100; i++)
{
tcs = new TaskCompletionSource<object>();
Update(i);
await tcs.Task;
}
}
void Update(int i)
{
//asynchronous - returns immediately
}
void UpdateComplete()//called from another thread
{
tcs.TrySetResult(null);
//unblock further calls to Update();
}
Post the updates into the thread pool using QueueUserWorkItem
Have a counter of the number of posted items.
Have main thread wait on AutoResetEvent
When Each update finishes decrement the count under lock.
When the count hits 0 Set the AutoResetEvent to awake the main thread
I didn't post any code cos I assumed you can google how to do each bit, if not comment and I can add code
I am working on a legacy application that is built on top of NET 3.5. This is a constraint that I can't change.
I need to execute a second thread to run a long running task without locking the UI. When the thread is complete, somehow I need to execute a Callback.
Right now I tried this pseudo-code:
Thread _thread = new Thread(myLongRunningTask) { IsBackground = True };
_tread.Start();
// wait until it's done
_thread.Join();
// execute finalizer
The second option, which does not lock the UI, is the following:
Thread _thread = new Thread(myLongRunningTask) { IsBackground = True };
_tread.Start();
// wait until it's done
while(_thread.IsAlive)
{
Application.DoEvents();
Thread.Sleep(100);
}
// execute finalizer
Of course the second solution is not good cause it overcharge the UI.
What is the correct way to execute a callback when a _thread is complete? Also, how do I know if the thread was cancelled or aborted?
*Note: * I can't use the BackgroundWorker and I can't use the Async library, I need to work with the native thread class.
There are two slightly different kinds of requirement here:
Execute a callback once the long-running task has completed
Execute a callback once the thread in which the long-running task was running has completed.
If you're happy with the first of these, the simplest approach is to create a compound task of "the original long-running task, and the callback", basically. You can even do this just using the way that multicast delegates work:
ThreadStart starter = myLongRunningTask;
starter += () => {
// Do what you want in the callback
};
Thread thread = new Thread(starter) { IsBackground = true };
thread.Start();
That's very vanilla, and the callback won't be fired if the thread is aborted or throws an exception. You could wrap it up in a class with either multiple callbacks, or a callback which specifies the status (aborted, threw an exception etc) and handles that by wrapping the original delegate, calling it in a method with a try/catch block and executing the callback appropriately.
Unless you take any special action, the callback will be executed in the background thread, so you'll need to use Control.BeginInvoke (or whatever) to marshal back to the UI thread.
I absolutely understand your requirements, but you've missed one crucial thing: do you really need to wait for the end of that thread synchronously? Or maybe you just need to execute the "finalizer" after thread's end is detected?
In the latter case, simply wrap the call to myLongRunningTask into another method:
void surrogateThreadRoutine() {
// try{ ..
mytask();
// finally { ..
..all 'finalization'.. or i.e. raising some Event that you'll handle elsewhere
}
and use it as the thread's routine. That way, you'll know that the finalization will occur at the thread's and, just after the end of the actual job.
However, of course, if you're with some UI or other schedulers, the "finalization" will now run on yours thread, not on the "normal threads" of your UI or comms framework. You will need to ensure that all resources are external to your thread-task are properly guarded or synchronized, or else you'll probably clash with other application threads.
For instance, in WinForms, before you touch any UI things from the finalizer, you will need the Control.InvokeRequired (surely=true) and Control.BeginInvoke/Invoke to bounce the context back to the UI thread.
For instance, in WPF, before you touch any UI things from the finalizer, you will need the Dispatcher.BeginInvoke..
Or, if the clash could occur with any threads you control, simple proper lock() could be enough. etc.
You can use a combination of custom event and the use of BeginInvoke:
public event EventHandler MyLongRunningTaskEvent;
private void StartMyLongRunningTask() {
MyLongRunningTaskEvent += myLongRunningTaskIsDone;
Thread _thread = new Thread(myLongRunningTask) { IsBackground = true };
_thread.Start();
label.Text = "Running...";
}
private void myLongRunningTaskIsDone(object sender, EventArgs arg)
{
label.Text = "Done!";
}
private void myLongRunningTask()
{
try
{
// Do my long task...
}
finally
{
this.BeginInvoke(Foo, this, EventArgs.Empty);
}
}
I checked, it's work under .NET 3.5
You could use the Observer Pattern, take a look here:
http://www.dofactory.com/Patterns/PatternObserver.aspx
The observer pattern will allow you, to notify other objects which were previously defined as observer.
A very simple thread of execution with completion callback
This does not need to run in a mono behavior and is simply used for convenience
using System;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
public class ThreadTest : MonoBehaviour
{
private List<int> numbers = null;
private void Start()
{
Debug.Log("1. Call thread task");
StartMyLongRunningTask();
Debug.Log("2. Do something else");
}
private void StartMyLongRunningTask()
{
numbers = new List<int>();
ThreadStart starter = myLongRunningTask;
starter += () =>
{
myLongRunningTaskDone();
};
Thread _thread = new Thread(starter) { IsBackground = true };
_thread.Start();
}
private void myLongRunningTaskDone()
{
Debug.Log("3. Task callback result");
foreach (int num in numbers)
Debug.Log(num);
}
private void myLongRunningTask()
{
for (int i = 0; i < 10; i++)
{
numbers.Add(i);
Thread.Sleep(1000);
}
}
}
Try to use ManualRestEvent to signal of thread complete.
Maybe using conditional variables and mutex, or some functions like wait(), signal(), maybe timed wait() to not block main thread infinitely.
In C# this will be:
void Notify()
{
lock (syncPrimitive)
{
Monitor.Pulse(syncPrimitive);
}
}
void RunLoop()
{
for (;;)
{
// do work here...
lock (syncPrimitive)
{
Monitor.Wait(syncPrimitive);
}
}
}
more on that here:
Condition Variables C#/.NET
It is the concept of Monitor object in C#, you also have version that enables to set timeout
public static bool Wait(
object obj,
TimeSpan timeout
)
more on that here:
https://msdn.microsoft.com/en-us/library/system.threading.monitor_methods(v=vs.110).aspx
I have a button that on click event I get some information from the network.
When I get information I parse it and add items to ListBox. All is fine, but when I do a fast double-click on button, it seems that two background workers are running and after finishing all work, items in the list are dublicated.
I want to do so that if you click button and the proccess of getting information is in work, this thread is stopping and only after first work is completed the second one is beginning.
Yes, I know about AutoResetEvent, but when I used it it helped me only one time and never more. I can't implement this situation and hope that you will help me!
Now I even try to make easier but no success :( : I added a flag field(RefreshDialogs)(default false), when the user clicks on button, if flag is true(it means that work is doing), nothing is doing, but when flag field is set to false, all is fine and we start a new proccess.
When Backgroundwork completes, I change field flag to false(it means that user can run a new proccess).
private void Message_Refresh_Click(object sender, EventArgs e)
{
if (!RefreshDialogs)
{
RefreshDialogs = true;
if (threadBackgroundDialogs.WorkerSupportsCancellation)
{
threadBackgroundDialogs.CancelAsync();
}
if (!threadBackgroundDialogs.IsBusy)
{
downloadedDialogs = 0;
threadBackgroundDialogs = new BackgroundWorker();
threadBackgroundDialogs.WorkerSupportsCancellation = true;
threadBackgroundDialogs.DoWork += LoadDialogs;
threadBackgroundDialogs.RunWorkerCompleted += ProcessCompleted;
threadBackgroundDialogs.RunWorkerAsync();
}
}
}
void ProcessCompleted(object sender, RunWorkerCompletedEventArgs e)
{
RefreshDialogs = false;
}
So you want to keep the second process running while the first works, but they shouldn't disturb each other? And after the first one finishes the second one continues?
Crude way: While loop:
if (!RefreshDialogs)
{
RefreshDialogs = true;
this becomes:
while(RefreshDialogs)
{
}
RefreshDialogs = true;
After you set it false the second process wwill jump out of the while. (Note this is extremly inefficent since both processes will be running all the time, i'm pretty sure the second one will block the first one, but with multitasking now it shouldn't, if it block use a Dispatcher.Thread)
Elegant way: Use A Semaphore
http://msdn.microsoft.com/de-de/library/system.threading.semaphore%28v=vs.80%29.aspx
If you find it impossible to have both processes running at the same time, or want another way:
Add an Array/List/int and when the second process notices there is the first process running, like with your bool, increase your Added variable, and at the end of the process, restart the new process and decrese the variable:
int number;
if (!RefreshDialogs)
{
RefreshDialogs = true;
your code;
if(number > 0)
{
number--;
restart process
}
}
else
{
number++;
}
I have to admit, i like my last proposal the most, since its highly efficent.
Make your thread blocking. That is easy;
lock(someSharedGlobalObject)
{
Do Work, Exit early if cancelled
}
This way other threads will wait until the first thread releases the lock. They will never execute simultaneously and silently wait until they can continue.
As for other options; why not disable the button when clicked and re-enable it when the backgroundworker completes. Only problem is this does not allow for cancelling the current thread. The user has to wait for it to finish. It does make any concurrency go away very easily.
How about this approach?
Create a request queue or counter which will be incremented on every button click. Every time that count is > 0. Start the background worker. When the information comes, decrement the count and check for 0. If its still > 0 restart the worker. In that your request handler becomes sequential.
In this approach you may face the problem of continuous reference of the count by two threads, for that you may use a lock unlock condition.
I hav followed this approach for my app and it works well, hope it does the same for you.
I'm not an Windows Phone expert, but as I see it has support for TPL, so following code would read nicely:
private object syncRoot =new object();
private Task latestTask;
public void EnqueueAction(System.Action action)
{
lock (syncRoot)
{
if (latestTask == null)
latestTask = Task.Factory.StartNew(action);
else
latestTask = latestTask.ContinueWith(tsk => action());
}
}
Use can use semaphores
class TheClass
{
static SemaphoreSlim _sem = new SemaphoreSlim (3);
static void Main()
{
for (int i = 1; i <= 5; i++)
new Thread (Enter).Start (i);
}
static void Enter (object name)
{
Console.WriteLine (name + " wants to enter");
_sem.Wait();
Console.WriteLine (name + " has entered!");
Thread.Sleep (1000 * (int) name );
Console.WriteLine (name + " is leaving");
_sem.Release(); }
}
}
I found the solution and thanks to #Giedrius. Flag RefreshingDialogs is set to true only when proccess is at the end, when I added items to Listbox. The reason why I'am using this flag is that state of process changes to complete when the asynchronous operation of getting content from network(HttpWebRequest, method BeginGetRequestStream) begins, but after network operaion is complete I need to make UI operations and not only them(parse content and add it to Listbox)My solution is:
private object syncRoot = new object();
private Task latestTask;
public void EnqueueAction(System.Action action)
{
lock (syncRoot)
{
if (latestTask == null)
{
downloadedDialogs = 0;
latestTask = Task.Factory.StartNew(action);
}
else if(latestTask.IsCompleted && !RefreshingDialogs)
{
RefreshingDialogs = true;
downloadedDialogs = 0;
latestTask = Task.Factory.StartNew(action);
}
}
}
private void Message_Refresh_Click(object sender, EventArgs e)
{
Action ac = new Action(LoadDialogs2);
EnqueueAction(ac);
}
I am currently writing my first program on C# and I am extremely new to the language (used to only work with C so far). I have done a lot of research, but all answers were too general and I simply couldn't get it t work.
So here my (very common) problem:
I have a WPF application which takes inputs from a few textboxes filled by the user and then uses that to do a lot of calculations with them. They should take around 2-3 minutes, so I would like to update a progress bar and a textblock telling me what the current status is.
Also I need to store the UI inputs from the user and give them to the thread, so I have a third class, which I use to create an object and would like to pass this object to the background thread.
Obviously I would run the calculations in another thread, so the UI doesn't freeze, but I don't know how to update the UI, since all the calculation methods are part of another class.
After a lot of reasearch I think the best method to go with would be using dispatchers and TPL and not a backgroundworker, but honestly I am not sure how they work and after around 20 hours of trial and error with other answers, I decided to ask a question myself.
Here a very simple structure of my program:
public partial class MainWindow : Window
{
public MainWindow()
{
Initialize Component();
}
private void startCalc(object sender, RoutedEventArgs e)
{
inputValues input = new inputValues();
calcClass calculations = new calcClass();
try
{
input.pota = Convert.ToDouble(aVar.Text);
input.potb = Convert.ToDouble(bVar.Text);
input.potc = Convert.ToDouble(cVar.Text);
input.potd = Convert.ToDouble(dVar.Text);
input.potf = Convert.ToDouble(fVar.Text);
input.potA = Convert.ToDouble(AVar.Text);
input.potB = Convert.ToDouble(BVar.Text);
input.initStart = Convert.ToDouble(initStart.Text);
input.initEnd = Convert.ToDouble(initEnd.Text);
input.inita = Convert.ToDouble(inita.Text);
input.initb = Convert.ToDouble(initb.Text);
input.initc = Convert.ToDouble(initb.Text);
}
catch
{
MessageBox.Show("Some input values are not of the expected Type.", "Wrong Input", MessageBoxButton.OK, MessageBoxImage.Error);
}
Thread calcthread = new Thread(new ParameterizedThreadStart(calculations.testMethod);
calcthread.Start(input);
}
public class inputValues
{
public double pota, potb, potc, potd, potf, potA, potB;
public double initStart, initEnd, inita, initb, initc;
}
public class calcClass
{
public void testmethod(inputValues input)
{
Thread.CurrentThread.Priority = ThreadPriority.Lowest;
int i;
//the input object will be used somehow, but that doesn't matter for my problem
for (i = 0; i < 1000; i++)
{
Thread.Sleep(10);
}
}
}
I would be very grateful if someone had a simple explanation how to update the UI from inside the testmethod. Since I am new to C# and object oriented programming, too complicated answers I will very likely not understand, I'll do my best though.
Also if someone has a better idea in general (maybe using backgroundworker or anything else) I am open to see it.
First you need to use Dispatcher.Invoke to change the UI from another thread and to do that from another class, you can use events.
Then you can register to that event(s) in the main class and Dispatch the changes to the UI and in the calculation class you throw the event when you want to notify the UI:
class MainWindow : Window
{
private void startCalc()
{
//your code
CalcClass calc = new CalcClass();
calc.ProgressUpdate += (s, e) => {
Dispatcher.Invoke((Action)delegate() { /* update UI */ });
};
Thread calcthread = new Thread(new ParameterizedThreadStart(calc.testMethod));
calcthread.Start(input);
}
}
class CalcClass
{
public event EventHandler ProgressUpdate;
public void testMethod(object input)
{
//part 1
if(ProgressUpdate != null)
ProgressUpdate(this, new YourEventArgs(status));
//part 2
}
}
UPDATE:
As it seems this is still an often visited question and answer I want to update this answer with how I would do it now (with .NET 4.5) - this is a little longer as I will show some different possibilities:
class MainWindow : Window
{
Task calcTask = null;
void buttonStartCalc_Clicked(object sender, EventArgs e) { StartCalc(); } // #1
async void buttonDoCalc_Clicked(object sender, EventArgs e) // #2
{
await CalcAsync(); // #2
}
void StartCalc()
{
var calc = PrepareCalc();
calcTask = Task.Run(() => calc.TestMethod(input)); // #3
}
Task CalcAsync()
{
var calc = PrepareCalc();
return Task.Run(() => calc.TestMethod(input)); // #4
}
CalcClass PrepareCalc()
{
//your code
var calc = new CalcClass();
calc.ProgressUpdate += (s, e) => Dispatcher.Invoke((Action)delegate()
{
// update UI
});
return calc;
}
}
class CalcClass
{
public event EventHandler<EventArgs<YourStatus>> ProgressUpdate; // #5
public TestMethod(InputValues input)
{
//part 1
ProgressUpdate.Raise(this, status); // #6 - status is of type YourStatus
// alternative version to the extension for C# 6+:
ProgressUpdate?.Invoke(this, new EventArgs<YourStatus>(status));
//part 2
}
}
static class EventExtensions
{
public static void Raise<T>(this EventHandler<EventArgs<T>> theEvent,
object sender, T args)
{
if (theEvent != null)
theEvent(sender, new EventArgs<T>(args));
}
}
#1) How to start the "synchronous" calculations and run them in the background
#2) How to start it "asynchronous" and "await it": Here the calculation is executed and completed before the method returns, but because of the async/await the UI is not blocked (BTW: such event handlers are the only valid usages of async void as the event handler must return void - use async Task in all other cases)
#3) Instead of a new Thread we now use a Task. To later be able to check its (successfull) completion we save it in the global calcTask member. In the background this also starts a new thread and runs the action there, but it is much easier to handle and has some other benefits.
#4) Here we also start the action, but this time we return the task, so the "async event handler" can "await it". We could also create async Task CalcAsync() and then await Task.Run(() => calc.TestMethod(input)).ConfigureAwait(false); (FYI: the ConfigureAwait(false) is to avoid deadlocks, you should read up on this if you use async/await as it would be to much to explain here) which would result in the same workflow, but as the Task.Run is the only "awaitable operation" and is the last one we can simply return the task and save one context switch, which saves some execution time.
#5) Here I now use a "strongly typed generic event" so we can pass and receive our "status object" easily
#6) Here I use the extension defined below, which (aside from ease of use) solve the possible race condition in the old example. There it could have happened that the event got null after the if-check, but before the call if the event handler was removed in another thread at just that moment. This can't happen here, as the extensions gets a "copy" of the event delegate and in the same situation the handler is still registered inside the Raise method.
I am going to throw you a curve ball here. If I have said it once I have said it a hundred times. Marshaling operations like Invoke or BeginInvoke are not always the best methods for updating the UI with worker thread progress.
In this case it usually works better to have the worker thread publish its progress information to a shared data structure that the UI thread then polls at regular intervals. This has several advantages.
It breaks the tight coupling between the UI and worker thread that Invoke imposes.
The UI thread gets to dictate when the UI controls get updated...the way it should be anyway when you really think about it.
There is no risk of overrunning the UI message queue as would be the case if BeginInvoke were used from the worker thread.
The worker thread does not have to wait for a response from the UI thread as would be the case with Invoke.
You get more throughput on both the UI and worker threads.
Invoke and BeginInvoke are expensive operations.
So in your calcClass create a data structure that will hold the progress information.
public class calcClass
{
private double percentComplete = 0;
public double PercentComplete
{
get
{
// Do a thread-safe read here.
return Interlocked.CompareExchange(ref percentComplete, 0, 0);
}
}
public testMethod(object input)
{
int count = 1000;
for (int i = 0; i < count; i++)
{
Thread.Sleep(10);
double newvalue = ((double)i + 1) / (double)count;
Interlocked.Exchange(ref percentComplete, newvalue);
}
}
}
Then in your MainWindow class use a DispatcherTimer to periodically poll the progress information. Configure the DispatcherTimer to raise the Tick event on whatever interval is most appropriate for your situation.
public partial class MainWindow : Window
{
public void YourDispatcherTimer_Tick(object sender, EventArgs args)
{
YourProgressBar.Value = calculation.PercentComplete;
}
}
You're right that you should use the Dispatcher to update controls on the UI thread, and also right that long-running processes should not run on the UI thread. Even if you run the long-running process asynchronously on the UI thread, it can still cause performance issues.
It should be noted that Dispatcher.CurrentDispatcher will return the dispatcher for the current thread, not necessarily the UI thread. I think you can use Application.Current.Dispatcher to get a reference to the UI thread's dispatcher if that's available to you, but if not you'll have to pass the UI dispatcher in to your background thread.
Typically I use the Task Parallel Library for threading operations instead of a BackgroundWorker. I just find it easier to use.
For example,
Task.Factory.StartNew(() =>
SomeObject.RunLongProcess(someDataObject));
where
void RunLongProcess(SomeViewModel someDataObject)
{
for (int i = 0; i <= 1000; i++)
{
Thread.Sleep(10);
// Update every 10 executions
if (i % 10 == 0)
{
// Send message to UI thread
Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Normal,
(Action)(() => someDataObject.ProgressValue = (i / 1000)));
}
}
}
Everything that interacts with the UI must be called in the UI thread (unless it is a frozen object). To do that, you can use the dispatcher.
var disp = /* Get the UI dispatcher, each WPF object has a dispatcher which you can query*/
disp.BeginInvoke(DispatcherPriority.Normal,
(Action)(() => /*Do your UI Stuff here*/));
I use BeginInvoke here, usually a backgroundworker doesn't need to wait that the UI updates. If you want to wait, you can use Invoke. But you should be careful not to call BeginInvoke to fast to often, this can get really nasty.
By the way, The BackgroundWorker class helps with this kind of taks. It allows Reporting changes, like a percentage and dispatches this automatically from the Background thread into the ui thread. For the most thread <> update ui tasks the BackgroundWorker is a great tool.
If this is a long calculation then I would go background worker. It has progress support. It also has support for cancel.
http://msdn.microsoft.com/en-us/library/cc221403(v=VS.95).aspx
Here I have a TextBox bound to contents.
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Debug.Write("backgroundWorker_RunWorkerCompleted");
if (e.Cancelled)
{
contents = "Cancelled get contents.";
NotifyPropertyChanged("Contents");
}
else if (e.Error != null)
{
contents = "An Error Occured in get contents";
NotifyPropertyChanged("Contents");
}
else
{
contents = (string)e.Result;
if (contentTabSelectd) NotifyPropertyChanged("Contents");
}
}
You are going to have to come back to your main thread (also called UI thread) in order to update the UI.
Any other thread trying to update your UI will just cause exceptions to be thrown all over the place.
So because you are in WPF, you can use the Dispatcher and more specifically a beginInvoke on this dispatcher. This will allow you to execute what needs done (typically Update the UI) in the UI thread.
You migh also want to "register" the UI in your business, by maintaining a reference to a control/form, so you can use its dispatcher.
Thank God, Microsoft got that figured out in WPF :)
Every Control, like a progress bar, button, form, etc. has a Dispatcher on it. You can give the Dispatcher an Action that needs to be performed, and it will automatically call it on the correct thread (an Action is like a function delegate).
You can find an example here.
Of course, you'll have to have the control accessible from other classes, e.g. by making it public and handing a reference to the Window to your other class, or maybe by passing a reference only to the progress bar.
Felt the need to add this better answer, as nothing except BackgroundWorker seemed to help me, and the answer dealing with that thus far was woefully incomplete. This is how you would update a XAML page called MainWindow that has an Image tag like this:
<Image Name="imgNtwkInd" Source="Images/network_on.jpg" Width="50" />
with a BackgroundWorker process to show if you are connected to the network or not:
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
public partial class MainWindow : Window
{
private BackgroundWorker bw = new BackgroundWorker();
public MainWindow()
{
InitializeComponent();
// Set up background worker to allow progress reporting and cancellation
bw.WorkerReportsProgress = true;
bw.WorkerSupportsCancellation = true;
// This is your main work process that records progress
bw.DoWork += new DoWorkEventHandler(SomeClass.DoWork);
// This will update your page based on that progress
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
// This starts your background worker and "DoWork()"
bw.RunWorkerAsync();
// When this page closes, this will run and cancel your background worker
this.Closing += new CancelEventHandler(Page_Unload);
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
BitmapImage bImg = new BitmapImage();
bool connected = false;
string response = e.ProgressPercentage.ToString(); // will either be 1 or 0 for true/false -- this is the result recorded in DoWork()
if (response == "1")
connected = true;
// Do something with the result we got
if (!connected)
{
bImg.BeginInit();
bImg.UriSource = new Uri("Images/network_off.jpg", UriKind.Relative);
bImg.EndInit();
imgNtwkInd.Source = bImg;
}
else
{
bImg.BeginInit();
bImg.UriSource = new Uri("Images/network_on.jpg", UriKind.Relative);
bImg.EndInit();
imgNtwkInd.Source = bImg;
}
}
private void Page_Unload(object sender, CancelEventArgs e)
{
bw.CancelAsync(); // stops the background worker when unloading the page
}
}
public class SomeClass
{
public static bool connected = false;
public void DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker bw = sender as BackgroundWorker;
int i = 0;
do
{
connected = CheckConn(); // do some task and get the result
if (bw.CancellationPending == true)
{
e.Cancel = true;
break;
}
else
{
Thread.Sleep(1000);
// Record your result here
if (connected)
bw.ReportProgress(1);
else
bw.ReportProgress(0);
}
}
while (i == 0);
}
private static bool CheckConn()
{
bool conn = false;
Ping png = new Ping();
string host = "SomeComputerNameHere";
try
{
PingReply pngReply = png.Send(host);
if (pngReply.Status == IPStatus.Success)
conn = true;
}
catch (PingException ex)
{
// write exception to log
}
return conn;
}
}
For more information: https://msdn.microsoft.com/en-us/library/cc221403(v=VS.95).aspx