Does using dispatcher.Invoke make my thread safe? - wpf

In my WPF app I have a long running upload running, which raises progress events as it goes which updates a progress bar. The user also has a chance of cancelling the upload, or it might go wrong. These are all async events, so they need to be executed using Dispatcher.Invoke in order to update the UI.
So the code looks like this, ish:
void OnCancelButtonClicked(object sender, EventArgs e)
{
upload.Cancel();
_cancelled = true;
view.Close();
view.Dispose();
}
void OnProgressReceived(object sender, EventArgs<double> e)
{
Dispatcher.Invoke(() =>
{
if (!cancelled)
view.Progress = e.Value;
}
}
Supposing that setting view.Progress on a disposed view is going to throw an error, is this code thread safe? i.e. if a user clicks cancel while the progress is updating, he/she will have to wait until the progress has been updated, and if the progress is updated during execution of OnCancelButtonClicked, the Dispatcher.Invoke call will cause the view.Progress update to be queued til after _cancelled is set, so I won't get a problem there.
Or do I need a lock to be safe, a la:
object myLock = new object();
void OnCancelButtonClicked(object sender, EventArgs e)
{
lock(myLock)
{
upload.Cancel();
_cancelled = true;
view.Close();
view.Dispose();
}
}
void OnProgressReceived(object sender, EventArgs<double> e)
{
Dispatcher.Invoke(() =>
{
lock(myLock)
{
if (!cancelled)
view.Progress = e.Value;
}
}
}

You don't have to add a lock. Dispatcher.Invoke and BeginInvoke requests will not run in the middle of other code (that's the whole point of them).
Just two things to consider:
BeginInvoke may be more appropriate in this case, Invoke will queue the request and then block the calling thread until the UI thread becomes idle and finishes executing the code, BeginInvoke will only queue the request without blocking.
Some operations, especially operations that open windows (including message boxes) or do inter-process communication may allow the queued dispatcher operations to run.
EDIT: first, I don't have citations because the MSDN pages on the subject are unfortunately very low on details - but I have written test programs to check the behavior of BeginInvoke and everything I write here is the result of those tests.
Now, to expand on the second point we first need to understand what the dispatcher does. Obviously this is a very simplified explanation.
Any Windows UI works by processing messages; For example when the user moves the mouse over a window the system will send that window a WM_MOUSEMOVE message.
The system send the message by adding it a queue, each thread may have a queue, all windows created by the same thread share the same queue.
In the heart of every Windows program there's a loop called "message loop" or "message pump", this loop reads the next message from the queue and calls the appropriate window's code to process that message.
In WPF this loop and all the related processing handled by the Dispatcher.
An application can either be in the message loop waiting for the next message or it could be doing something. That is why when you have a long calculation all the thread's windows become unresponsive - the thread is busy working and doesn't return to the message loop to process the next message.
Dispatcher.Invoke and BeginInvoke works by queuing the requested operation and executing it the next time the thread returns to the message loop.
That is why Dispatcher.(Begin)Invoke can't "inject" code in the middle of your method, you won't get back to the message loop until your method returns.
BUT
Any code can run a message loop. When you call anything that runs a message loop the Dispatcher will be called and can run the (Begin)Invoke operations.
What kinds of code has a message loop?
Anything that has a GUI or that accepts user input, for example dialog boxes, message boxes, drag&drop etc. - if those didn't have a message loop then the app would have been unresponsive and unable to handle user input.
Inter-process communication that uses windows messages behind the scenes (most inter-process communication methods, including COM, use them).
Anything else that takes a long time and doesn't freeze the system (the fast that the system isn't frozen is proof it's processing messages).
So, to summarize:
the Dispatcher can't just drop code into your thread, it can only execute code when the application is in the "message loop".
Any code you write doesn't have message loops unless you explicitly wrote them.
Most UI code doesn't have it's own message loop, for example if you call Window.Show and then do some long calculation the window will only appear after the calculation is finished and the method returns (and the app returns to the message loop and processes all the messages required to open and draw a window).
But any code that interacts with the user before it returns (MessageBox.Show, Window.ShowDialog) has to have a message loop.
Some communication code (network and inter-process) uses message loops, some doesn't, depending on the specific implementation you are using.

This is an interesting question. Items executed in the dispatcher are queued and execute on the same thread as UI interaction. Here's the best article on this subject:
http://msdn.microsoft.com/en-us/library/ms741870.aspx
If I were to venture a guess, I would say that Dispatcher.Invoke(Action) probably queues an atomic work item, so it's likely going to be ok, however I'm not sure if it wraps up your UI event handler in an atomic action item for instance:
//Are these bits atomic? Not sure.
upload.Cancel();
_cancelled = true;
For safety's sake I would personally lock, but your question warrants more research. Might need a dive in reflector to figure out for sure.
As an aside, I'd probably optimize your lock a bit.
Dispatcher.Invoke(() =>
{
if (!cancelled)
{
lock(myLock)
{
if(!cancelled)
view.Progress = e.Value;
}
}
}
But that's probably overkill :)

Related

SQLDependency - does not fire while being busy

Is it normal behavior that a SQLDependency onchange event is not fired if its thread is too busy?
private void NotificationOnChanged(...)
{
// get database results
// simulate long process
Thread.Sleep(10000);
}
During the sleep i add a new row and the notification is lost after the sleep expires.
Must I spawn a new single thread to do the work and use a flag to detect if new notifications arrived to restart the it?
This behavior is an artifact of the implementation on the ADO.net notification listener. See http://rusanu.com/2008/01/04/sqldependencyonchange-callback-timing/.
The SqlDependency internal thread that posts the WAITFOR(RECEIVE) is not going to post another one until the callback returns. So you have to do as little processing as possible and return in the OnChange event. Definetely nothing blocking.
Alternatively you can use the lower level SqlNotificationRequest that lets you manage everyting, including the notification handling. But you'll have to manage everything. See http://technet.microsoft.com/en-us/library/ms190270(v=sql.105).aspx

How do I run code in a thread that called a parameterless Application.Run()?

I want to render a chart with the DevExpress ChartControl via the WiForm DrawToBitmap() function on a separate thread.
I try something like:
Form yourForm;
Thread thread = new Thread( () =>
{
yourForm = new HiddenForm();
Application.Run(yourForm);
});
thread.ApartmentState = ApartmentState.STA;
thread.Start();
yourForm.Invoke(chartRenderingFunction)
And simple make sure the Hidden never actually gets displayed. However, I don't need that hidden form, and there is a parameterless form of Application.Run(). However, if I run that, it doesn't return. So my question is once I call Application.Run() inside a thread, how do I inject code in it?
Well, you actually really do need that hidden window. The only way to get code to run on that thread. Somebody must call PostMessage() and that requires a window handle. Your Invoke() call makes that call. You really should use BeginInvoke() instead, there's no point in starting a thread if you are going to wait for the call to complete.
Using Application.Run(yourForm) is going to make the window visible. You can stop it from becoming visible by overriding the SetVisibleCore() method in your HiddenForm class:
protected override void SetVisibleCore(bool value) {
if (!this.IsHandleCreated) {
CreateHandle();
value = false;
ThreadReady.Set();
}
base.SetVisibleCore(value);
}
The CreateHandle() call is necessary to make sure that the window is created so it can process the PostMessage() notifications. Also note the added AutoResetEvent (ThreadReady), you are going to have to call ThreadReady.WaitOne() after calling the thread's Start() method to ensure that your BeginInvoke() call is going to work. Dispose the form to get the thread to exit or call Application.Exit().
Last but not least, be very careful with using non-trivial controls on that thread. A chart control certainly is not indicated. You'll have long-lasting problems if that control uses the SystemEvents class for example. Your worker thread will get it to raise events on that worker thread. But it won't be around anymore after the chart is printed. You'll now get the events fired on an arbitrary threadpool thread, very nasty. A deadlock is a common mishap, particularly apt to trigger when locking the workstation.

Locking dispatcher

Is it necessary to lock code snippet where multiple threads access same wpf component via dispatcher?
Example:
void ladder_OnIndexCompleted(object sender, EventArgs args)
{
lock (locker)
{
pbLadder.Dispatcher.Invoke(new Action(() => { pbLadder.Value++; }));
}
}
pbLadder is a progress bar and this event can be raised from multiple threads in the same time.
You should not acquire a lock if you're then going to marshal to another thread in a synchronous fashion - otherwise if you try to acquire the same lock in the other thread (the dispatcher thread in this case) you'll end up with a deadlock.
If pbLadder.Value is only used from the UI thread, then you don't need to worry about locking for thread safety - the fact that all the actions occur on the same thread isolates you from a lot of the normal multi-threading problems. The fact that the original action which caused the code using pbLadder.Value to execute occurred on a different thread is irrelevant.
All actions executed on the Dispatcher are queued up and executed in sequence on the UI thread. This means that data races like that increment cannot occur. The Invoke method itself is thread-safe, so also adding the action to the queue does not require any locking.
From MSDN:
Executes the specified delegate with the specified arguments
synchronously on the thread the Dispatcher is associated with.
and:
The operation is added to the event queue of the Dispatcher at the
specified DispatcherPriority.
Even though this one is pretty old it was at the top of my search results and I'm pretty new (4 months since I graduated) so after reading other peoples comments, I went and spoke with my senior coder. What the others are saying above is accurate but I felt the answers didn't provide a solution, just information. Here's the feedback from my senior coder:
"It's true that the Dispatcher is running on its own thread, but if another thread is accessing an object that the dispatcher wants to access then all UI processing stops while the dispatcher waits for the access. To solve this ideally, you want to make a copy of the object that the dispatcher needs to access and pass that to the dispatcher, then the dispatcher is free to edit the object and won't have to wait on the other thread to release their lock."
Cheers!

Problem with WPF Application and slow GUI response

I've been analyzing a WPF application which basically fetch data from a server and display the data in the GUI.
This code is not mine, and the application has a problem related with slow response from the GUI, I'm trying to find the reason for that problem.
I want to share with you my idea of which the problem could be and I'll like to hear what do you think about it, whether it makes any sense or not.
To get the data from the server, the application is using 7 threads (this is done in this way mostly because of the application logic, so don't pay too much attention to why 7 and not just one...), now, each thread is created by calling a method, called CreateThreadForTask()
public void StartAllThreads()
{
this.CreateThreadForTask(Tasks.Task1);
this.CreateThreadForTask(Tasks.Task2);
this.CreateThreadForTask(Tasks.Task3);
this.CreateThreadForTask(Tasks.Task4);
this.CreateThreadForTask(Tasks.Task5);
this.CreateThreadForTask(Tasks.Task6);
this.CreateThreadForTask(Tasks.Task7);
}
public void CreateThreadForTask(Tasks task)
{
... // this part of the code is not important
//! Initialize and start timer
timer = null;
timer = new DispatcherTimer();
timer.Tick += new EventHandler(RunMainSyncForTask);
timer.Start();
}
public void RunMainSyncForTask(object s, EventArgs e)
{
int sec = int.Parse(AppSettings.GetSetting("syncInterval"));
timer.Interval = new TimeSpan(0, 0, sec);
//threadCaller is a background worker
threadCaller = InitializeThread();
threadCaller.DoWork += DoWorkEventHandler(StartSync);
threadCaller.RunWorkerAsync();
}
When I was debugging the code I noticed that all the threads are created using a DispatcherTimer; what I think is that the application is creating 7 DispatcherTimer's and is linking the Tick event of the timers with the RunMainSyncForTask() method, which inside, create a background worker that fetch the data from the server and save that data to a local database.
Now, this was taken from the MSDN
The DispatcherTimer is reevaluated at the top of every Dispatcher loop.
Timers are not guaranteed to execute exactly when the time interval occurs, but they are guaranteed to not execute before the time interval occurs. This is because DispatcherTimer operations are placed on the Dispatcher queue like other operations. When the DispatcherTimer operation executes is dependent on the other jobs in the queue and their priorities.
So, based on that I believe that the application is spamming threads every time a timer does a tick event, and this is done 7 times simultaneously; and all these operations, because of the DispatcherTimer nature, are being added to the Dispatcher queue, which makes the GUI response slow, due to the Dispatcher being busy.
Also, another problem with the application is that, when it runs, it takes about 90-95% of the CPU, I think that if my hypothesis is right, this could be also the cause of for this problem.
So if you can share some insides about this I'll appreciate it.
Thanks.
You're getting the 90-95% CPU because you've instituted a form of busy waiting through a crazy web of threading calls.
If you're using this StartSync logic to post status notifications or get data back to the GUI, you're jumping through a lot of hoops. If you're on .Net 4.0 you should switch to the Task Parallel Library and let the framework handle all of this for you. It also supports graceful cancellation, etc.
If you don't wish to use TPL, I would suggest instead passing the Windows Dispatcher (use the usual suspects: Invoke or BeginInvoke) or SynchronizationContext (asynchronously with Post, synchronously with Send) to the individual tasks for use for these tasks which must be done in the GUI.

Prevent UI from freezing without additional threads

What solutions do I have if I want to prevent the UI from freezing while I deserialize a large number of UI elements in WPF? I'm getting errors complainig that the objects belong on the UI Thread when I'm trying to load them in another thread. So, what options do I have to prevent the Vista "Program not responding" error while I'm loading my UI data? Can I rely on a single-threaded solution, or am I missing something regarding perhaps multiple UI Threads?
If you only use a single thread then the UI will freeze while you do any amount of processing.
If you use a BackgroundWorker thread you'll have more control over what happens & when.
To update the UI you need to use Dispatcher.Invoke from your background thread to marshal the call across the thread boundary.
Dispatcher.Invoke(DispatcherPriority.Background,
new Action(() => this.TextBlock.Text = "Processing");
You can turn the flow of control on its head using DispatcherFrames, allowing a deserialization to proceed on the UI thread in the background.
First you need a way to get control periodically during deserialization. No matter what deserializer you are using, it will have to call property sets on your objects, so you can usually add code to the property setters. Alternatively you could modify the deserializer. In any case, make sure your code is called frequently enough
Each time you receive control, all you need to do is:
Create a DispatcherFrame
Queue an event to the dispatcher using BeginInvoke that sets Continue=false on the frame
Use PushFrame to start the frame running on the Dispatcher
In addition, when calling the deserializer itself make sure you do it from Dispatcher.BeginInvoke, or that your calling code doesn't hold any locks etc.
Here's how it would look:
public partial class MyWindow
{
SomeDeserializer _deserializer = new SomeDeserializer();
byte[] _sourceData;
object _deserializedObject;
...
void LoadButton_Click(...)
{
Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
{
_deserializedObject = _deserializer.DeserializeObject(_sourceData);
}));
}
}
public class OneOfTheObjectsBeingDeserializedFrequently
{
...
public string SomePropertyThatIsFrequentlySet
{
get { ... }
set { ...; BackgroundThreadingSolution.DoEvents(); }
}
}
public class BackgroundThreadingSolution
{
[ThreadLocal]
static DateTime _nextDispatchTime;
public static void DoEvents()
{
// Limit dispatcher queue running to once every 200ms
var now = DateTime.Now;
if(now < _nextDispatchTime) return;
_nextDispatchTime = now.AddMilliseconds(200);
// Run the dispatcher for everything over background priority
var frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
{
frame.Continue = false;
}));
Dispatcher.PushFrame(frame);
}
}
Checking DateTime.Now in DoEvents() isn't actually required for this technique to work, but will improve performance if SomeProperty is set very frequently during deserialization.
Edit: Right after I wrote this I realized there is an easier way to implement the DoEvents method. Instead of using DispatcherFrame, simply use Dispatcher.Invoke with an empty action:
public static void DoEvents()
{
// Limit dispatcher queue running to once every 200ms
var now = DateTime.Now;
if(now < _nextDispatchTime) return;
_nextDispatchTime = now.AddMilliseconds(200);
// Run the dispatcher for everything over background priority
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new Action(() => {}));
}
Here is a wonderful blog posting from Dwane Need that discusses all the available options for working with UI elements amongst multiple threads.
You really haven't given enough detail to give a good prescription. For example, why are you creating UI elements yourself at all instead of using databinding? You might have a good reason, but without more details it's hard to give good advice. As another example of detail that would be useful, are you looking to build complex deeply nested control hierarchies for each piece of data or do you just need to draw a simple shape?
I had a similar problem with my panel which was moving its items. The UI was freezing because I was using a DispatcherTimer at priority Loaded. The problem is gone as soon as I changed it to DispatcherPriority.Input.
You can still make your long processing in a separate thread, but when finished you have to synchronize with the UI thread by calling Dispatcher.BeginInvoke(your_UI_action_here)
Recommendations from the OldNewThing blog.
It is best if you do go the threaded route, to have one GUI thread and spawn your work load off to another thread that when finishes reports back to the main GUI thread that its done. The reason for this is because you will not get into thread issues with your GUI interface.
So One GUI Thread
Many worker threads that do the work.
If any of your threads do hang the user is in direct control over your application can can close down the thread without effecting his experience with the application interface. This will make him happy because your user will feel in control other than him constantly click THAT STOP BUTTON AND IT WONT STOP SEARCHING.
Try freezing your UIElements. Frozen objects can be passed between threads without encountering an InvalidOperationException, so you deserialize them & freeze them on a background thread before using them on your UI thread.
Alternatively, consider dispatching the individual deserializations back to the UI thread at background priority. This isn't optimal, since the UI thread still has to do all of the work to deserialize these objects and there's some overhead added by dispatching them as individual tasks, but at least you won't block the UI - higher priority events like input will be able to be interspersed with your lower priority deserialization work.

Resources