I have strange issue reported by users and once reproduced by me.
I have form with various buttons and each button performs long operation.
When new buttons are clicked old operation will stops and new will be started.
And i noticed strange behaviour:
When i am clicking button sometimes operation doesnot started.
Operation cannot be started because next code:
if (!Worker.IsBusy)
{
RunReload();
}
else
{
isWorkerPendingForNewJob = true;
Worker.CancelAsync();
}
Cancel is called few times but my worker is always busy!
When i brake my project execution i noticed that it stops on lock section.
Inside this lock i am just creating some objects that are used for all processes.
Brackpoints on image never hits.
Why backgroundworked is always busy and locked on this line?
When you call CancelAsync(), it just set the flag CancellationPending to true. You must manually check periodically this flag in your BackgroundWorker work function and interrupt it yourself. Are you doing this already?
Here is the related MSDN page.
Also, you must ensure that WorkerSupportsCancellation is true to support CancelAsync.
Related
I have registered an error handler in my application that shows a user dialog MessageBox when an unhandled exception occurs. It's connected to the Application.DispatcherUnhandledException event and thus happens on the UI thread. Now I've seen a situation where an exception is thrown regularly, once per second, and new dialogs kept popping up. I was trying to prevent this with a lock, but since it's all on the same thread, this doesn't have any effect. An additional sleep lock on the same thread obviously led to a single blocked MessageBox on the screen.
The MessageBox seems to free the UI thread for other MessageBoxes to appear. How can I prevent that without blocking the thread?
The user has the choice to continue or exit the application. When continuing, the next queued MessageBox should appear, it should not be discarded. If too many messages show up in a time, the user can still decide to exit the application.
The problem here is not with the message box. It is that what happens when the message box is still open, while another exception has occurred. In which case, your DispatcherUnhandledException handler gets re-entered on the same thread.
However, the user hasn't made a decision yet about the previous error, the previous message box is still waiting for his input. Your call stack looks like this:
=> DispatcherUnhandledExceptionHandler (current)
MessageBox.Show
DispatcherUnhandledExceptionHandler (previous)
Clearly, you cannot return from DispatcherUnhandledExceptionHandler (previous), without returning from DispatcherUnhandledExceptionHandler (current) first: you're inside a nested call on the same thread. And you cannot return from DispatcherUnhandledExceptionHandler (current) without confirming this fist with the user, back to the egg.
I can think of just one way of solving this, while sticking with your question requirements. It's to display the message box on another thread and block the main thread's message loop while waiting for the user's choice. This way, no more exceptions can occur on the main thread, until you obtain the user's consent regarding the current exception:
Application.Current.DispatcherUnhandledException += (s, e) =>
{
this.IsEnabled = false; // disable the main window
try
{
var result = Task.Factory.StartNew(
() => MessageBox.Show(
e.Exception.Message, "Continue?",
MessageBoxButton.YesNo),
TaskCreationOptions.LongRunning).Result; // this blocks
if (result == MessageBoxResult.Yes)
e.Handled = true;
}
finally
{
this.IsEnabled = true; // enable the main window
}
};
This is ugly from the UI experience prospective, but it gives you the desired workflow.
Message boxes are still windows that run on your thread, so they have to pump window messages (a Modal Message Loop) in order to be repainted when required, moved, handle keyboard input (e.g. Tab to move between controls), mouse input. They still dispatch messages to other windows on the same thread, to ensure that the window that owns them is repainted. The owning window is disabled, so input messages simply result in the default sound being played, but timers will still be fired and any sent or posted messages will still be processed.
The usual source of such problems is that you have a System.Windows.Forms.Timer or WPF DispatcherTimer attached to the window. Other possibilities include background threads using Invoke or BeginInvoke to perform some operation on the UI thread.
My program runs a test over a serial connection. After I click the RUN TEST button everything works great. The RUN TEST button disappears and the STOP button pops up. Data collection runs as expected. My problem is that the STOP button doesn't respond. All of my testing code is run under the RUN TEST button click event. Is this uninterruptible by my second button?
Note: I use the whateverButton.enable and whateverButton.visible properties. Is there another one I need to set to get this to work?
runButton.Enabled = false;
runButton.Visible = false;
STOPbutton.Enabled = true;
STOPbutton.Visible = true;
The rest of the program is to big to fully include.
Any help with this would greatly appreciated.
Let me guess - you disable the "Run", enable the "Stop", perform your task, reverse the enable/disable on "Run" and "Stop"?
Your issue is that the UI is not updated because the UI thread is busy running your task.
Use BackgroundWorker or Task.Run to spawn a new thread for the task, some significant refactoring may need to happen to take UI interaction out of the background thread and to support cancelling.
I am trying to understand a certain longstanding concept in Windows Forms re: UI programming; following code is from Chris Sells' Windows Forms Programming book (2nd Ed., 2006):
void ShowProgress(string pi, int totalDigits, int digitsSoFar) {
// Display progress in UI
this.resultsTextBox.Text = pi;
this.calcToolStripProgressBar.Maximum = totalDigits;
this.calcToolStripProgressBar.Value = digitsSoFar;
if( digitsSoFar == totalDigits ) {
// Reset UI
this.calcToolStripStatusLabel.Text = "Ready";
this.calcToolStripProgressBar.Visible = false;
}
// Force UI update to reflect calculation progress
this.Refresh();
}
This method is part of small sample application that has another long-running method which calculates Pi. Each time a cluster of digits are calculated, ShowProgress() is called to update the UI. As explained in the book, this code is the "wrong" way of doing things, and causes the UI to freeze when the application is minimized and then brought into the foreground again, causing the system to ask the application to repaint itself.
What I don't understand: Since this.Refresh() is being called repeatedly, why doesn't it process any system repaint event that is waiting for attention?
And a follow-up question: When I add Application.DoEvents() immediately following this.Refresh(), the freeze-up problem disappears. This is without having to resort to Invoke/BeginInvoke, etc. Any comments?
Basically, the reason for this is the way Windows handles messages - it does this in a synchronous way in an internal message loop.
The point is that there was a message that triggered your code. For example a button click. Your application is in the middle of handling the message. From within this handler, you force the refresh which puts another WM_PAINT in the message queue. When your handler finishes, the message loop will surely pick it up and dispatch, thus repainting the control. But your code is not finished, in fact it loops calling your ShowProgress, causing WM_PAINT being queued forever.
On the other hand, the DoEvents() causes an independent instance of the message loop to fire. It's fired from within your code which means that the call stack looks like this:
outer message loop -> your code -> inner message loop.
The inner message loop processes all pending messages, including the WM_PAINT (thus the control is redrawn) but it is dangerous - as it will dispatch all other pending messages, including button clicks, menu clicks or event closing your application with the X at the top-right corner. Unfortunately, there's no easy way to make the loop to process the WM_PAINT only which means that calling DoEvents() exposes your application to subtle potential problems involving unexpected user activity during the execution of your code which triggers the DoEvents.
I have a Windows Form and a class with two simple methods that run recursively in a nondeterministic way (meaning that it's unknown which recursion will be called, both can call the other)... Now, there are some points during that recursion at which I want to pause the execution and wait for a user to click on the "Next Step" button. Only after the button is pressed should the recursive functions continue. The class runs on a separate thread so it doesn't block the UI.
During that pause, the Form would simply retrieve the value from the class and display it in a listbox. Then after the button is pressed, the recursion continues until the next Pause(). I need this so the user can see what is happening in the recursion step by step. Also I need to be able to put Pause() anywhere in the recursive method (even multiple times) without causing any side-effects...
The only way that comes to my mind is to call Pause() method in which a loop checks some locked flag and then sleeps for some time (the button would then set the flag), but I had some bad experiences with Thread.Sleep() in Windows Forms (locking the UI) so I am looking at another options.
Is there any clean way to do this?
Use a ManualResetEvent that is initialized to true, so it begins set. At a well-known place in one method or the other (or both), wait for the event. Most of the time, the event will be set so the background thread will continue immediately. When the user clicks Pause, however, reset the event, causing the background thread to block the next time it reaches the event. When the user next clicks "Resume", set the event, allowing the background thread to continue again.
There's no reason that the UI thread should ever block in this scenario.
Use a AutoResetEvent object.
Call the .WaitOne method on it from your thread to pause it, and call the .Set method on it from your button to unpause it.
This is a good place to use a Mutex in a non-standard way. Just have your background thread take and release the Mutex when it's in a position where it's ok to wait.
Have your GUI thread take the Mutex when it wants to block the background thread, and release it when it's ok for it to run.
That way the background thread will wait when it should, and will simple blaze in and out of the Mutex when it's allowed to run.
Think of the 'right to run' as a resource that the critical section is protecting.
like this
// this object has to be visible to both threads
System.Threading.Mutex mtx = new Mutex();
// worker thread does this wherever it's ok for it to pause
mtx.WaitOne();
mtx.ReleaseMutex();
// main thread does this to pause the worker
Mtx.WaitOne();
// main thread does this this to unpause it.
mtx.ReleaseMutex();
Did some searches here & on the 'net and haven't found a good answer yet. What I'm trying to do is call a button twice within the same class in C#.
Here's my scenario -
I have a form with a button that says "Go". When I click it the 1st time, it runs through some 'for' loops (non-stop) to display a color range. At the same time I set the button1.Text properties to "Stop". I would like to be able to click the button a 2nd time and when that happens I would like the program to stop. Basically a stop-and-go button. I know how to do it with 2 button events, but would like to utilize 1 button.
Right now the only way to end the program is the X button on the form.
I've tried different things and haven't had much luck so far so wanted to ask the gurus here how to do it.
BTW, this is a modification of a Head First Labs C# book exercise.
Thanks!
~Allen
You would need to use Multithreading (launch the process intensive code asynchronously in a separate thread), for instance, using the BackgroundWorker object in .NET 2+. This would be necessary because your UI will not respond to the user's click until the loop running in the Start method is completed. It is quite irrelevant if you use the same button or another one to toggle the process, because the processor is busy processing the loop.
The BackgroundWorker has a property called WorkerSupportsCancellation which needs to be true in this scenario. When the user clicks Stop you would invoke the CancelAsync method of the BackgroundWorker.
See MSDN for a good example. Also DreamInCode has a good tutorial which seems quite similar to your requirement.
Why not create two buttons, hide one when the other is visible? That should be a lot of easier to handle.
Or you can add a bool field to indicate which operation branch to execute.
One simple solution would be to add a boolean member to your form that is, e.g., true when the button says "Go" and false when the button says "Stop".
Then, in your button's event handler, check that boolean value. If the value is true, then start your operation and set the value to false when you change the button's text to say "stop". Vice-versa for the other case. :)
There are other techniques that I might prefer if this were production code, perhaps including considering the design of the form more carefully, but as this is clearly a learning exercise I believe that a simple boolean flag indicating the current state of the form is just what you're looking for.
Note that I would strongly discourage you from checking the value of the button text to determine what state the object is in. Whenever possible, as a general rule of good design, you want your visual state to be "decoupled" from your underlying object's state. That is to say, your visual widgets can depend on your underlying objects, but your underlying objects should not depend on your visual widgets. If you tested the text of the button, your underlying logic would depend on your visual state and that would violate this general rule.
If your problem is related to the fact that you can't cancel the operation while it's being performed, you'll want to look into using a BackgroundWorker to perform your long-running activity.
Another option would be to check the current text on your button to determine what to do:
void btnStartStop_Click(Object sender, EventArgs e)
{
if (btnStartStop.Text == "Go")
{
btnStartStop.Text = "Stop";
// Go code here
}
else
{
btnStartStop.Text = "Go";
// Stop code here
}
}
Are you getting your second button click event? Put a breakpoint in your click handler and run your code. When you click the second time, do you ever hit your breakpoint?
If your loop is running continuously, and it is in your button click handler, then your loop is running in the UI thread. You probably don't get to "see" the second button click until after the loop is completed. In addition to the branch code that you see above, try either inserting a DoEvents in your loop processing (this is a place where your loop will temporarly give up control so that messages can be processed). Or, (better) have a look at the backgroundworker class -- do most of your processing in a different thread, so that you UI can remain responsive to button clicks.
Cerebrus is right about using the Background Worker thread. However if you are doing a WPF app then it won't be able to update the UI directly. To get around this you can call Dispatcher.BeginInvoke on the main control/window.
Given code like:
Private Delegate Sub UpdateUIDelegate(<arguments>)
Private Sub CallUpdateUI(<arguments>)
control.Dispatcher.BeginInvoke(Windows.Threading.DispatcherPriority.Background, New UpdateUIDelegate(AddressOf UpdateUI), <arguments>)
End Sub
Private Sub UpdateUI(<arguments>)
'update the UI
End Sub
You can call CallUpdateUI from the Background Worker thread and it will get the main thread to perform UpdateUI.
You could set the Tag property on the button to a boolean indicating whether the next action should be "Stop" or "Go", and reset it each time you click the button. It's an Object property, though, so you'll have to cast it to bool when you read it.