a bit of a juvenile question...
I realise that in a Winforms app, long running code should be executed in its own thread. How does one accomplish this on say, a button click event?
I want to do this in an effort to free up the UI thread so that I can simultaneously overlay the current form with a semi-transparent modal dialog form. I've aleady created the modal dialog form with a neat loading GIF located in the centre that works perfectly on a button click event on its own.
The reason I've chosen this method, is because (1) I want to block any user interaction with the form while the code is being executed, and (2) provide the user with an indication that processing is underway (I dont know how to judge how long a particular piece of code will take to execute, hence opting for an indefinite loading indicator gif).
Also, on the topic of executing code in separate threads...should this not apply to any code, or only specifically to long-running code?
I would really appreciate any help on this matter! thank you!
One of the simplest ways is to use a BackgroundWorker component. Add a BackgroundWorker to your form, add an event handler for the DoWork event, and call the long-running function from there. You can start it in your button click event handler by calling the RunWorkerAsync method on the BackgroundWorker component.
In order to know when the operation is ready, set up a handler for the RunWorkerCompleted event.
private void Button_Click(object sender, EventArgs e)
{
myBackgroundWorker.RunWorkerAsync();
}
private void myBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
// long-running operation here; will execute on separate thread
}
private void myBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// operation is ready
}
I'll answer the second half of your question (as Fredrik has already explained the BackgroundWorker):
No, it does not make sense to move a task to a separate thread unless the task is long running.
Running a task on a separate thread always incurrs extra overheads. It might take more of the UI thread's time to kick off the thread and handle the task completion then it would have to simply do the task in the first place.
Like any programming technique, you have to weigh up the costs and benefits for the particular situation.
I will attempt to answer the second part of your question, based on my own experience.
You will generally only use threads in one of three circumstances:
On operations which will block for noticeable periods of time on system calls (File/Socket IO, etc.)
On long running operations where a loss of UI responsiveness is undesirable.
With multiple long running operations, where exploiting a multi-core environment is desirable.
As Andrew Shepherd says, there are overheads for using Threads.
Threads complicate things dramatically. Never thread for the sake of threading.
Related
I am experimenting with a simple ViewModel-first based WPF application and some primitive navigation logic. The application consists of two views (screens). One screen contains a button "Go forward" and the other a button "Go backward". By pressing one of the buttons a delegate command is invoked, which in turn causes the shell view-model to switch the active screen. Screen 1 switches to Screen 2, whereas Screen 2 switches to Screen 1.
The problem with this approach is, that it introduces a race condition. When clicking fast enough there is a chance that the corresponding action (go forward/go backward) is executed twice, thus causing the application to fail. The interesting thing about that is that the screen has already been changed, but the UI doesn't reflect the state changes instantaneously. Until now I never had experienced this kind of gap and I made this experiment just to prove, that a single-threaded (dispatched) WPF application is automatically thread-safe.
Does somebody have an explanation for this odd behavior? Is the WPF binding mechanism too slow, so that the button can be pressed a second time, until the UI has updated itself to represent the new screen state?
I have no idea how to fix this according to the recommendations for developing mvvm applications. There is no way to synchronize the code, because there is only one thread. I hope you can help me, because now I feel very unsecure with relying on the WPF data binding and templating system.
Zip archive containing the project files
MainWindow.xaml:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<DataTemplate DataType="{x:Type local:Screen1}">
<local:View1/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:Screen2}">
<local:View2/>
</DataTemplate>
</Window.Resources>
<Window.DataContext>
<local:ShellViewModel/>
</Window.DataContext>
<Grid>
<ContentControl Content="{Binding CurrentScreen}"/>
</Grid>
</Window>
The ShellViewModel containing a "go forward" and "go backward" method:
Public Class ShellViewModel
Inherits PropertyChangedBase
Private _currentScreen As Object
Public Property Screens As Stack(Of Object) = New Stack(Of Object)()
Public Sub New()
Me.Screens.Push(New Screen1(Me))
Me.GoForward()
End Sub
Property CurrentScreen As Object
Get
Return _currentScreen
End Get
Set(value)
_currentScreen = value
RaisePropertyChanged()
End Set
End Property
Public Sub GoBack()
Log("Going backward.")
If (Me.Screens.Count > 2) Then
Throw New InvalidOperationException("Race condition detected.")
End If
Log("Switching to Screen 1")
Me.Screens.Pop()
Me.CurrentScreen = Me.Screens.Peek()
End Sub
Public Sub GoForward()
Log("Going forward.")
If (Me.Screens.Count > 1) Then
Throw New InvalidOperationException("Race condition detected.")
End If
Log("Switching to Screen 2.")
Me.Screens.Push(New Screen2(Me))
Me.CurrentScreen = Me.Screens.Peek()
End Sub
End Class
The Screen class containing just a delegate command to start the action:
Public Class Screen1
Inherits PropertyChangedBase
Private _clickCommand As ICommand
Private _shellViewModel As ShellViewModel
Public Sub New(parent As ShellViewModel)
_shellViewModel = parent
End Sub
Public ReadOnly Property ClickCommand As ICommand
Get
If _clickCommand Is Nothing Then
_clickCommand = New RelayCommand(AddressOf ExecuteClick, AddressOf CanExecute)
End If
Return _clickCommand
End Get
End Property
Private Function CanExecute(arg As Object) As Boolean
Return True
End Function
Private Sub ExecuteClick(obj As Object)
Threading.Thread.SpinWait(100000000)
_shellViewModel.GoForward()
End Sub
End Class
There is no weird race condition
I've run your code. There is one thread. The main one.
One thread = no race condition.
Why do you want to prove the following ?
I made this experiment just to prove, that a single-threaded
(dispatched) WPF application is automatically thread-safe.
It's a bullet proof fact. One thread = thread safe (as long as you don't share data process wide, but then it's not thread safety anymore).
Binding and Method no supporting successive calls
In fact, your methods GoBack and GoForward are not supporting successive calls. They should be called one after another.
Thread safety here doesn't imply that your methods cannot be call twice in a row. If there is any task queue in the process, methods can be called twice.
What you may intend to prove is maybe the following:
Clicks are captured and processed in line, without any task queuing between
the click, the property changed event raised, the dispatcher
invocation, the binding / display refresh.
It's clearly Wrong!
When you call Dispatcher.BeginInvoke or Invoke, it's using internally a queue of tasks. And nothing prevent you from queuing twice the same task coming from two similar clicks for example.
To be frank, I was unable to reproduce your bug. I think it's the same thread that captures clicks that dispatch it to your code and then display it on screen. However since task for click events, display refresh are in the same queue, it is theoretically possible to enqueue two clicks before screen change. However :
I cannot click fast enough to beat my cpu.
I don't think the SpinWait are needed.
Something may miss in my configuration.
Why not making your methods supporting successive calls ?
GoBack and GoBackward could check a status and do nothing if the current status is not valid.
You could have used:
1. Two screens both instantiated from the start.
2. A bool to indicate the current state (Forward or Back).
3. An enum to be more clearer in code.
4. A state machine.. no! I'm kidding.
Note: Why using a Stack to push and pop screen(only one by the way) ? and...
in case, you add another thread:
Stack pop / push are not thread safe.
Instead use ConcurrentStack<T>
Simulation
Even when the UI thread is frozen or doing something, another inputs are being collected. Try this out (Sorry for C# but you get the point):
private void ButtonClick(object sender, EventArgs args)
{
Debug.WriteLine("start");
Thread.Sleep(6000);
Debug.WriteLine("End");
}
Click the button, then place a breakpoint on the Start line, click the button again before the UI thread unfreezes. and you will see that exactly 6 seconds after your first click the breakpoint gets hit.
Explanation
The UI thread can obviously only perform 1 action at a time, but it has to be optimized for multithreading - meaning it queues it's actions. Therefore any PropertyChanged (or any handler at all including the OnClick) is only queueing the action for the UI thread. It doesn't jump out of your code to update the UI elements in the middle of your setter. If you call Thread.Sleep after the setter you will see that you don't see any change - because the UI thread didn't get to invoke the update yet.
Why is this important
In your code you first Push a screen and then set is as current, calling propertyChanged. That does not change the screens immediately, it just queues it for the update. There is no guarantee that another click doesn't get scheduled before that.
You could also achieve freezing your UI thread by calling PropertyChanged a million times causing it to freeze during the update itself. Yet the clicks in the meantime would be collected.
So your "safepoint" - the place where it is safe that no other click can be scheduled now - is not after the Setter is finished, but after the Loaded Event is called on the new window.
How to fix
Read
Fab
's answer :)
Dont think that just because the UI thread is blocked at the moment nothing gets in. If you want to disable inputs while something is being calculated you do need to disable the inputs manually.
Possible solutions
Set IsEnabled, Visibility, IsHitTestVisible
Some Overlay or whatever
Boolean parameter, that could globally allow or disallow all methods coming (basically a lock)
I cannot reproduce the described behavior - double clicking causes the app to first "go backward", and then "go forward" at my side. Nevertheless, I think that expecting the button to disappear before the user can click it for the second time is not a good design (especially in case of devices that for instance have a separate "double-click" button), and I would personally never rely on that.
What I think is the best way to proceed in this situation is to properly implement the CanExecute method, so that it not only returns true (which by the way is most likely redundant), but rather queries the _shellViewModel whether it's in a state allowing to invoke the method called by ExecuteClick (in case of GoForward it should return true if there is only one element on the stack). I cannot test that (because I cannot reproduce the behavior in question), but I'm pretty sure that even if the user clicks the same button twice, the second call to CanExecute will occur after the first call to ExecuteClick, thus the model will be guaranteed to be "up-to-date" (the result will be false and GoForward will not be called again).
#Pavel Kalandra:
While it is possible for a simple click event-handler to be queued multiple times, even if the UI thread is blocked, I can't reproduce this behavior with a delegate command. Hence I assume that the WPF framework does handle the invocation of an command a little bit differently compared to a simple click event-handler. Moreover, in your example the click event is already queued before the execution of the event-handler has finished. In my situation this is not the case.
To prove this assumption I made a further experiment: By using a command that blocks the UI thread for a few seconds and then shows a message, you can see that it is not possible to invoke it multiple times during its invocation. I believe that the WPF framework is somehow preventing this from happening. Therefore both scenarios aren't comparable to one.
But I think that your explanation is still correct. Pushing the screen causes the PropertyChanged-event to be fired, but the screen is not updated immediately. Indeed the associated job is pushed onto the dispatcher queue and is scheduled. As a consequence there is a short time span during which it is possible to invoke the command a second time.
#Fab:
When you strongly rely on the accepted definition of a race condition, then there shouldn't be one in my sample application. But for simplicity purposes I would like to call it still a race condition because the scheduling of jobs makes the execution nondeterministic.
Nevertheless, the assumption I was intended to prove, is wrong. I wanted to prove it because of threading problems we are currently faced with. Our application simulates multiple modal methods at the same time, therefore it relies on multiple threads. Because the interactions, a user is allowed to, aren't properly synchronized there is a high chance for race conditions to happen (synchronizing them is not an option because of other reasons).
At the moment I am working on a prototype which doesn't use threads so heavily. My hope was, that by executing everything on the dispatcher thread race conditions (or similar problems) shouldn't be possible. At least for a ViewModel-first approach this seems to be wrong because of the way the WPF is scheduling binding updates.
I have used a simple scenario where it is easy to provide a fix to the potential "race condition". But in general it won't be easy to write a Bulletproof WPF application. A flag to indicate the direction (forward/backward) won't be enough when dealing with multiple screens. But the command delegate could check if it is invoked from the active screen.
PS: As long as I rely exclusively on the dispatcher thread to execute actions, I see no need for using a ConcurrentStack ;-)
I have come across another similar issue, that proves that UI scheduling can in fact introduce race conditions even if the application is single-threaded.
In the example a piece of code is called, that is supposed to be atomic. Because scheduling is used using different priorities, the code may be interrupted in the middle of execution.
This is an example that I found in a similar form in our production code. Users have mentioned an issue that is spontaneously occuring. I have found out then that a SelectionChanged-event was interrupting a piece of code that was supposed to be executed as a block.
public partial class MainWindow : Window
{
private bool inBetweenMethod;
public MainWindow()
{
InitializeComponent();
this.timer = new DispatcherTimer(DispatcherPriority.Loaded);
this.timer.Interval = TimeSpan.FromMilliseconds(10);
this.timer.Tick += Timer_Tick;
this.timer.Start();
this.MethodThatIsSupposedToBeAtomic();
}
private void Timer_Tick(object sender, EventArgs e)
{
if (inBetweenMethod)
{
throw new Exception("Method was interrupted in the middle of execution".);
}
}
private void MethodThatIsSupposedToBeAtomic()
{
inBetweenMethod = true;
Dispatcher.Invoke(new Action(() =>
{
for (int i = 0; i < 100; i++)
{
Console.WriteLine("iterating");
}
}), DispatcherPriority.ContextIdle);
inBetweenMethod = false;
}
}
Im reading a WPF book and I see this code:
private void bgw1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
int percenti;
percenti = e.ProgressPercentage;
progressBar1.Value = percenti;
}
The question is simple.
if
ProgressBar belongs to UI Thread and
BackGroundWorker works with a Background Thread
Why are there no errors (like: The calling thread cannot access this object because a different thread owns it.)?
thanks.
Why are there no errors (like: The calling thread cannot access this object because a different thread owns it.)?
This is one of the main advantages to using BackgroundWorker. The BackgroundWorker component automatically marshals calls for progress and completion back to the synchronization context (thread) that starts the job.
In this case, that means that the event handlers for ProgressChanged (and the completion event) happen on the WPF UI thread.
The BackgroundWorker handles the thread context switch for you. The event BackgroundWorker.ProgressChanged will be raised on the UI-Thread and hence your callback bgw1_ProgressChanged will be called in the context of the UI-Thread.
This was the main purpose for the BackgroundWorker's existence: To make async work easy and straight forward in conjunction with a UI.
BackgroundWorker exists since .NET 1.0. Now that we live in 2012, we have the Task class and the Task Parallel Library and soon the c# async keyword as general means for everything async, wich makes the BackgroundWorker kind of obsolete or at least old school.
It is because you cannot make changes in the Do_work method of the background worker.
progress_changed event keeps updating what is happening in the other thread.
Bes to clear your concept through this link-->
[https://www.codeproject.com/Articles/99143/BackgroundWorker-Class-Sample-for-Beginners][1]
I'm relatively new to WPF. I'm examining some code that looks like this:
private void button_Click(object sender, RoutedEventArgs e)
{
//Queue on dispatcher in the background so it doesn't make the UI slow
Dispatcher.BeginInvoke(new dMyDelegate(PerformOperation), DispatcherPriority.Background);
}
From the comment, I'm guessing the original code felt that this was necessary to make the UI more responsive, however, my understanding is that Dispatcher.BeginInvoke simply runs something on the UI thread. Since the buttn_Click is already on the UI thread, what's the point? Perhaps I'm misunderstanding Dispatcher and BeginInvoke. I'm assumming that Dispatcher in this case, is the dispatcher owned by the class this method is in, which is MainWindow.xaml. Can someone enlighten me?
Thanks
Well, it's asking for "background" priority, so it's only going to get executed when any more important events have been processed... If this is part of a big screen refresh, it'll effectively wait until all of that has happened before executing. Even so, if it's going to be doing anything long-running (or making any potentially blocking calls) then you're right, it really shouldn't be running on the UI thread at all.
We've got a Model-View-Presenter setup with our .NET Compact Framework app. A standard CF Form is implementing the view interface, and passed into the constructor of the presenter. the presenter tells the form to show itself by calling view.Run(); the view then does a Show() on itself, and the presenter takes over again, loading up data and populating it into the view.
Problem is that the view does not finishing showing itself before control is returned to the presenter. since the presenter code blocks for a few seconds while loading data, the effect is that the form is not visible for a few seconds. it's not until after the presenter finishes it's data load that the form becomes visible, even though the form called Show() on itself before the presenter started its data loading.
In a standard windows environment, i could use the .Shown event on the form... but compact framework doesn't have this, and I can't find an equivalent.
Does anyone know of an even, a pinvoke, or some other way to get my form to be fully visible before kicking off some code on the presenter? at this point, i'd be ok with the form calling to the presenter and telling the presenter to start it's data load.
FYI - we're trying to avoid multi-threading, to cut down on complexity and resource usage.
The general rule is: never do anything blocking on the UI thread
The UI in Windows (and in Windows CE as well) has an asynchronous nature. Which means that most API calls do not necessarily do whatever they're supposed to do immediately. Instead, they generate a series of events, which are put into the event queue and later retrieved by the event pump, which is, essentially, an infinite loop running on the UI thread, picking events from the queue one by one, and handling them.
From the above, a conclusion can be drawn that if you continue to do something lengthy on the UI thread after requesting a certain action (i.e. showing the window in your case), the event pump cannot proceed with picking events (because you haven't returned control to it), and therefore, your requested action cannot complete.
The general approach is as follows: if you must do complex data transformation/loading/preparing/whatever, do it on a separate thread, and then use Control.BeginInvoke to inject a delegate into the UI thread, and touch the actual UI controls from inside that delegate.
Despite your irrational fear of "complexity" that multithreading brings with it, there is very little to be afraid of. Here's a little example to illustrate the point:
public void ShowUI()
{
theForm = new MyForm();
theForm.Show();
// BeginInvoke() will take a new thread from the thread pool
// and invoke our delegate on that thread
new Action( PrepareData ).BeginInvoke(null,null);
}
public void PrepareData()
{
// Prepare your data, do complex computation, etc.
// Control.BeginInvoke will put our delegate on the UI event queue
// to be retrieved and executed on the UI thread
theForm.BeginInvoke( new Action( PutDataInTheForm ) );
}
public void PutDataInTheForm()
{
theForm.textBox1.Text = "data is ready!";
}
While you may play with alternative solutions, the general idea always remains the same: if you do anything lengthy on the UI thread, your UI will "freeze". It will not even redraw itself as you add new UI elements on the screen, because redrawing is also an asynchronous process.
Therefore, you must do all the complex and long stuff on a separate thread, and only do simple, small, guaranteed to run fast things on the UI thread. There is no other alternative, really.
Hope this helps.
If your key problem is that the form won't paint before your presenter data loading methods are completed, and you have a call to this.Show() in your Form_Load, try putting Application.DoEvents() directly after this.Show() to force/allow the form to paint.
protected void Form_Load(blah blah blah)
{
this.Show();
Application.DoEvents();
... data loading methods ...
}
No need to create another thread if you don't want to (although a couple of seconds have to be dealt with somehow).
You can use the activated event. Because it will fire when the form is activated, you need a boolean local to the form to check wether or not the form has been created for the first time.
Another option for you is to disconnect the event handler right after you finish presenting the form.
In my WinForms application, I need to pop up a little custom dialog that stays on the screen for X amount of seconds and then disappears. So I use a System.Threading.Timer to invoke the _dialog.Close() method once the appropriate amount of time has elapsed. This of course means that I have to do the whole "if InvokeRequired BeginInvoke" dance which isn't really a problem.
What is a problem however is that my main thread might be off doing god knows what by the time the BeginInvoke is called. It might not get around to closing the window for quite a while. I don't need the window to close at a millisecond's notice, but within a second or so is really necessary.
So my question is how does BeginInvoke actually work itself into the main thread and how can I get around this odd limitation?
If your UI thread is busy for many seconds at a time, then:
You won't be able to close a window associated with that UI thread, without peppering your code with Application.DoEvents calls (a bad idea)
Your whole UI will be unresponsive during this time. The user won't be able to move any of the application's windows, and if the user drags other windows over the top of it and off again, you'll end up with an ugly mess while the UI waits to repaint itself.
Certainly use a System.Windows.Forms.Timer instead of a System.Threading.Timer for simplicity, but more urgently, look at fixing your code to avoid having such a busy UI thread.
UPDATE: The conclusion would seem to be that utilising ['BackgroundWorker](http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx) along with a System.Windows.Forms.Timer would be the best approach.
Best to use System.Windows.Forms.Timer for this purpose - this is precisely the sort of application it was designed for. Add one to the pop up form and start it as soon as the form is shown, then hide the form on the Tick event. This solution won't give you any threading issues because the timer runs purely on the UI thread.
Edit: If you want to move the logic outside of your popup form, then I recommend you just create an overload for the Show method within the form code that takes a timespan for its parameter and does the job of setting the Timers's interval and starting it.
Edit 2: If you're main (UI) thread is doing too much work and therefore blocking the message pump and not allowing the timer to fire, then it's the design that's the issue I'm afraid. Your UI thread should never be blocking for more than a fraction of a second. If you need to do serious work, do it in the background using a worker thread. In this case, because you are using WinForms, BackgroundWorker is probably the best option.
Create a dedicated thread and use Application.Run to create and show your form. This will start up a message pump on the second thread which is independent of the main thread. This can then close exactly when you want it, even if the main thread is blocked for any reason.
Invoke and BeginInvoke do get into the main thread by using a window message posted into that thread, waiting for it to be processed. Therefore, if the message pump of the main thread is not processing messages (e.g. busy), it will have to wait. You can mitigate this factor by calling Application.DoEvents() when doing time-consuming operations in the main thread, but that's not really a solution to the problem.
Edit: Sample from some splash screen code (the form requires no special code or logic):
private void ShowSplashInSeparateMessageQueue() {
Thread splash = new Thread(ShowSplashForm);
splash.IsBackground = true;
splash.Start();
}
private void ShowSplashForm() { // runs in a separate thread and message queue
using (SplashForm splashForm = new SplashForm()) {
splashForm.Load += AddDestroyTimer;
Application.Run(splashForm);
}
}
private void AddDestroyTimer(object sender, EventArgs e) {
Form form = (Form)sender;
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer(form.Container);
timer.Tick += delegate { form.Close(); };
timer.Interval = 5000;
timer.Start();
}
Invoke just places the delegate into the message queue of the thread you want to invoke it on. You could use the Dispatcher class to insert the delegate with a high priority, but there is no gurante that this will meet you timing constraints if the thread is doing a lot of work.
But this might be an indication that you are doing to much work on the user interface thread. Not responding for a second is a pain to a user. So you might think about moving some work out of the user interface thread.