I want to know what can be problem if i have the following POC...
public void DoProcess() // called as Do_Work
{
textUpdater = null;
try
{
SetButtonEnabled(false);
aHandler = new DataHandler();
aHandler.Initialize(_configuration);
aHandler.GetDataFromWebAndSave();
MessageBox.Show("completed");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + " \r\n\r\n" + ex.StackTrace);
}
SetButtonEnabled(true);
}
Usually a backgroundWorker process includes a loop where one can easily see whether cancel is called or not. In my case, i can't check ...
Say I CLOSE the windows form (containing above code). Will everything be terminated safely ??
If not, then how can i do it ?
(i guess other way could be 'use thread').
The thread proc of your backgroundworker doesn't have to have a loop. And it doesn't have to be cancelled to finish. It simply finishes when... the proc exits!
When it finishes, RunWorkerCompleted will be called.
I see a major problem in your call though: You manipulate your GUI from the background thread. This is a no-no! All manipulations of a GUI element must be made from the thread that created the element. In your case, use ReportProgress() to delegate status information to the ProgressChanged handler that will execute it in the foreground thread.
In addition, as Rewinder wrote, you can cancel the worker from FormClosing(). But if you never monitor CancellationPending from your worker proc, this is pointless.
If you want to be sure your backgroundworker is cancelled, you can do something like this:
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
myBackgroundWorker.CancelAsync();
}
Related
I created Backgroundworker to operate on serial port which uses some methods provided by different classes. I'd like to cancel a worker each time an exception from those methods occurs.
Actually, I have some idea how to do it, using events, but I am afraid it's not optimal solution or a good practice. In that case I should firing event in each method, which is not efficient in my opinion.
For ex., one from methods, ReceiveRecord looks like that:
public string ReceiveRecord()
{
try
{
var receivedLine = _serial.ReadLine();
return receivedLine;
}
catch (TimeoutException exception)
{
MessageBox.Show($"Error was occured: \r\n {exception.Message}", "Timeout error",
MessageBoxButton.OK, MessageBoxImage.Error);
// HERE i want to fire worker cancellation
}
return String.Empty;
}
Worker calls that methods periodically.
I considered returning false, when errors occurs, but I don't have ANY idea, how to do it, if method returns string...
Are there any simple method to fire DoWork cancellation from the catch fragment of code?
Don't catch the exception in the method. Let the caller handle it in BackgroundWorker's RunWorkerCompleted event.
See Background worker exception handling
The BackgroundWorker class has a WorkerSupportsCancellation boolean which tells the worker whether the worker supports cancellation or not. Enable this then in your backgroundworker DoWork event, check if CancellationPending, if true, end the thread, otherwise continue with normal operation.
Use the CancelAsync() function to set cancellation pending true. You would want to set this in your catch block.
In my example below, my background worker is in a while loop, but it should give you the right idea.
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
try
{
while (true)
{
if (bw.CancellationPending)
break;
do_state_machine();
Thread.Sleep(100);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
I have a WinForm load method that takes a long time to gather some data to display to the user.
I display a form with a large font with the word "Loading" while this method is executing.
However sometimes this error comes up and the "Loading" progress form does not close and then eventually my whole application will just exit:
Error creating window handle. at System.Windows.Forms.NativeWindow.CreateHandle(CreateParams cp)
Is there a better way to display my progress/loading form while I am executing code in the load method?
This is my code:
//I launch a thread here so that way the Progress_form will display to the user
//while the Load method is still executing code. I can not use .ShowDialog here
//or it will block.
//Progress_form displays the "Loading" form
Thread t = new Thread(new ThreadStart(Progress_form));
t.SetApartmentState(System.Threading.ApartmentState.STA);
t.IsBackground = true;
t.Start();
//This is where all the code is that gets the data from the database. This could
//take upwards of 20+ seconds.
//Now I want to close the form because I am at the end of the Load Method
try
{
//abort the Progress_form thread (close the form)
t.Abort();
//t.Interrupt();
}
catch (Exception)
{
}
A BackgroundWorker is a great way to perform a long running operation without locking the UI thread.
Use the following code to start a BackgroundWorker and display a loading form.
// Configure a BackgroundWorker to perform your long running operation.
BackgroundWorker bg = new BackgroundWorker()
bg.DoWork += new DoWorkEventHandler(bg_DoWork);
bg.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bg_RunWorkerCompleted);
// Start the worker.
bg.RunWorkerAsync();
// Display the loading form.
loadingForm = new loadingForm();
loadingForm.ShowDialog();
This will cause the following method to be executed on a background thread. Note that you cannot manipulate the UI from this thread. Attempting to do so will result in an exception.
private void bg_DoWork(object sender, DoWorkEventArgs e)
{
// Perform your long running operation here.
// If you need to pass results on to the next
// stage you can do so by assigning a value
// to e.Result.
}
When the long running operation completes, this method will be called on the UI thread. You can now safely update any UI controls. In your example, you would want to close the loading form.
private void bg_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Retrieve the result pass from bg_DoWork() if any.
// Note, you may need to cast it to the desired data type.
object result = e.Result;
// Close the loading form.
loadingForm.Close();
// Update any other UI controls that may need to be updated.
}
Ive successfully tested this on .NET 4.0. (WinForms) I'm reasonably certain that this will work on .NET 4.0+ and should be a useful code snippet to reuse in most of your projects that require closing forms at the end of a process.
private void SomeFormObject_Click(object sender, EventArgs e)
{
myWait = new YourProgressForm();//YourProgressForm is a WinForm Object
myProcess = new Thread(doStuffOnThread);
myProcess.Start();
myWait.ShowDialog(this);
}
private void doStuffOnThread()
{
try
{
//....
//What ever process you want to do here ....
//....
if (myWait.InvokeRequired) {
myWait.BeginInvoke( (MethodInvoker) delegate() { closeWaitForm(); } );
}
else
{
myWait.Close();//Fault tolerance this code should never be executed
}
}
catch(Exception ex) {
string exc = ex.Message;//Fault tolerance this code should never be executed
}
}
private void closeWaitForm() {
myWait.Close();
MessageBox.Show("Your Process Is Complete");
}
I would take the code that you have in your load method and place that into a thread. Setup a progress bar somewhere on your form and increment it at key stages in the code that's gathering the data - be careful not to do this in the thread itself though, i.e. don't tamper with ui elements in a separate thread, you'll need to invoke them using a delegate.
I have a method processData() that takes a large amount of data and does some work on it. There's a start button that initiates the processing. I need a cancel button that stops the processing wherever it's at. How can I implement something like that? The thing I don't get is how to make the cancel button usable once the processing has started since the rest of the UI is frozen when the function is running.
BackgroundWorker.CancelAsync Method is what you need. Here is a good example for you.
If you have got a time consuming process you will have to use a separate thread to handle that in order to support for cancellation. If you execute that time consuming process in the main thread(UI thread) it will be busy and won't take your cancellation request in to account until it finish that task. That's why you experience UI freezing.
If you use a backgroundWorker for your time consuming task and if you check the CancellationPending flag in the BackgroundWorker.DoWork method you could achieve what you want.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace BackgroundWorker
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
//mandatory. Otherwise will throw an exception when calling ReportProgress method
backgroundWorker1.WorkerReportsProgress = true;
//mandatory. Otherwise we would get an InvalidOperationException when trying to cancel the operation
backgroundWorker1.WorkerSupportsCancellation = true;
}
//This method is executed in a separate thread created by the background worker.
//so don't try to access any UI controls here!! (unless you use a delegate to do it)
//this attribute will prevent the debugger to stop here if any exception is raised.
//[System.Diagnostics.DebuggerNonUserCodeAttribute()]
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
//NOTE: we shouldn't use a try catch block here (unless you rethrow the exception)
//the backgroundworker will be able to detect any exception on this code.
//if any exception is produced, it will be available to you on
//the RunWorkerCompletedEventArgs object, method backgroundWorker1_RunWorkerCompleted
//try
//{
DateTime start = DateTime.Now;
e.Result = "";
for (int i = 0; i < 100; i++)
{
System.Threading.Thread.Sleep(50); //do some intense task here.
backgroundWorker1.ReportProgress(i, DateTime.Now); //notify progress to main thread. We also pass time information in UserState to cover this property in the example.
//Error handling: uncomment this code if you want to test how an exception is handled by the background worker.
//also uncomment the mentioned attribute above to it doesn't stop in the debugger.
//if (i == 34)
// throw new Exception("something wrong here!!");
//if cancellation is pending, cancel work.
if (backgroundWorker1.CancellationPending)
{
e.Cancel = true;
return;
}
}
TimeSpan duration = DateTime.Now - start;
//we could return some useful information here, like calculation output, number of items affected, etc.. to the main thread.
e.Result = "Duration: " + duration.TotalMilliseconds.ToString() + " ms.";
//}
//catch(Exception ex){
// MessageBox.Show("Don't use try catch here, let the backgroundworker handle it for you!");
//}
}
//This event is raised on the main thread.
//It is safe to access UI controls here.
private void backgroundWorker1_ProgressChanged(object sender,
ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage; //update progress bar
DateTime time = Convert.ToDateTime(e.UserState); //get additional information about progress
//in this example, we log that optional additional info to textbox
txtOutput.AppendText(time.ToLongTimeString());
txtOutput.AppendText(Environment.NewLine);
}
//This is executed after the task is complete whatever the task has completed: a) sucessfully, b) with error c)has been cancelled
private void backgroundWorker1_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
if (e.Cancelled) {
MessageBox.Show("The task has been cancelled");
}
else if (e.Error != null)
{
MessageBox.Show("Error. Details: " + (e.Error as Exception).ToString());
}
else {
MessageBox.Show("The task has been completed. Results: " + e.Result.ToString());
}
}
private void btoCancel_Click(object sender, EventArgs e)
{
//notify background worker we want to cancel the operation.
//this code doesn't actually cancel or kill the thread that is executing the job.
backgroundWorker1.CancelAsync();
}
private void btoStart_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
}
}
Use a BackgroundWorker.
Put the heavy code in the DoWork event.
The cancel button should call CancelAsync on the BackgroundWorker.
In the heacy code in DoWork check the CancellationPending property periodically. If the property is true you should abort the work.
stops the processing wherever it's at
If you mean that the process should stop immediately and not even wait for a moment where it checks a cancellation token, you may consider running the process in a separate AppDomain and kill it when you cancel.
Although this is perfectly possible, I would recommend a controlled termination as in the other answers, especially when your process changes external state.
Hello guys I have a question regardless a old code a client needed a update.
This code add a thread.sleep(500) to keep the service alive, is reading from a com port some calls, and sending a alarm to other pcs now this time when I was sending some information to the machine in question this error pops out
Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on.
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e) {
Thread.Sleep(500);
string data = port.ReadExisting();
//try
//{
if (textBox1.TextLength == 30000)
{
textBox1.Text = "";
}
//}
//catch (Exception) {}
this.BeginInvoke(new setTextDeleg(si_DataRecived), new object[]{
data});
}
This is the function that writes on the com machine, does making a exception to eat the error is ok, or is there another better way to handle it?
PD: Sorry for my bad english, this is on C# 2008 vs
You should modify GUI components like textboxes and labels only from the thread that created them which is the main thread. You may take a look at BackgroundWorker which simplifies this task in WinForms application. And here's another useful article illustrating the usage of the InvokeRequired property and the Invoke method.
It's not a good idea to simply swallow this exception. The exception is occurring because you are not allowed to modify UI components from any thread other than the UI thread (the thread that created them). Instead, check out this MSDN article on how to pass information between worker threads (your thread that sleeps) and UI threads to update the text box in the correct manner.
The problem is because Windows Forms Controls are not thread-safe, and it would seem that the control is not being invoked properly for a thread-safe call. You can use the BackgroundWorker class or you can invoke it yourself. Here is a small code example.
// Delegate used by our worker thread to invoke our control
private delegate void ProgressDelegate(int value);
// Callback method used for our delegate
private void ProgressCallback(int value) {
progressBar1.Value = value;
}
protected override void OnShown(EventArgs e) {
Thread thread = new Thread(new ThreadStart(MyThreadWorker));
thread.IsBackground = true;
thread.Start();
}
// Thread method
private void MyThreadWorker() {
// Setup the delegate
ProgressDelegate mydelegate = new ProgressDelegate(ProgressCallback);
// Do some work
int pos = 0;
do {
pos++;
// Make a thread-safe call to our control and invoke our callback on the original thread
// Original thread: The thread the form and control were created on
progressBar1.Invoke(mydelegate, pos);
} while (pos < 100);
}
I'm guessing what some of your other code looks like, but you could probably move this
if (textBox1.TextLength == 30000)
{
textBox1.Text = "";
}
to the si_DataRecived method, so that it gets executed as part of the BeginInvoke call, the target of which will execute on the main (UI) thread.
I have the following code in my worker thread (ImageListView below is derived from Control):
if (mImageListView != null &&
mImageListView.IsHandleCreated &&
!mImageListView.IsDisposed)
{
if (mImageListView.InvokeRequired)
mImageListView.Invoke(
new RefreshDelegateInternal(mImageListView.RefreshInternal));
else
mImageListView.RefreshInternal();
}
However, I get an ObjectDisposedException sometimes with the Invoke method above. It appears that the control can be disposed between the time I check IsDisposed and I call Invoke. How can I avoid that?
What you have here is a race condition. You're better off just catching the ObjectDisposed exception and be done with it. In fact, I think in this case it is the only working solution.
try
{
if (mImageListView.InvokeRequired)
mImageListView.Invoke(new YourDelegate(thisMethod));
else
mImageListView.RefreshInternal();
}
catch (ObjectDisposedException ex)
{
// Do something clever
}
There are implicit race conditions in your code. The control can be disposed between your IsDisposed test and the InvokeRequired test. There's another one between InvokeRequired and Invoke(). You can't fix this without ensuring the control outlives the life of the thread. Given that your thread is generating data for a list view, it ought to stop running before the list view disappears.
Do so by setting e.Cancel in the FormClosing event and signaling the thread to stop with a ManualResetEvent. When the thread completes, call Form.Close() again. Using BackgroundWorker makes it easy to implement the thread completion logic, find sample code in this post.
The reality is that with Invoke and friends, you can't completely protect against invoke on a disposed component, or then getting InvalidOperationException because of the missing handle. I haven't really seen an answer yet, like the one farther below, in any of the threads that addresses the real fundamental problem, which cant be completely solved by preemptive testing or using lock semantics.
Here's the normal 'correct' idiom:
// the event handler. in this case preped for cross thread calls
void OnEventMyUpdate(object sender, MyUpdateEventArgs e)
{
if (!this.IsHandleCreated) return; // ignore events if we arn't ready, and for
// invoke if cant listen to msg queue anyway
if (InvokeRequired)
Invoke(new MyUpdateCallback(this.MyUpdate), e.MyData);
else
this.MyUpdate(e.MyData);
}
// the update function
void MyUpdate(Object myData)
{
...
}
The fundemental problem:
In using the Invoke facility the windows message queue is used, which places a message in the queue to either wait or fire-and-forget the cross thread call exactly like Post or Send message. If there is a message ahead of the Invoke message that will invalidate the component and its window handle, or that got placed just after any checks you try to perform, then you are going to have a bad time.
x thread -> PostMessage(WM_CLOSE); // put 'WM_CLOSE' in queue
y thread -> this.IsHandleCreated // yes we have a valid handle
y thread -> this.Invoke(); // put 'Invoke' in queue
ui thread -> this.Destroy(); // Close processed, handle gone
y thread -> throw Invalid....() // 'Send' comes back, thrown on calling thread y
There is no real way to know that the control is about to remove itself fromthe queue, and nothing really reasonable you can do to "undo" the invoke. No matter how many checks you do or extra locks you make, you cant stop someone else form issuing something like a close, or deactivate. There are tons of senarios where this can happen.
A solution:
The first thing to realize is that the invoke is going to fail, no different than how a (IsHandleCreated) check would have ignored the event. If the goal is to protect the caller on the non-UI thread you will need to handle the exception, and treat it like any other call that didn't succeed (to keep app from crashing or do whatever. And unless going to rewrite/reroll Invoke facility, the catch is your only way to know.
// the event handler. in this case preped for cross thread calls
void OnEventMyWhatever(object sender, MyUpdateEventArgs e)
{
if (!this.IsHandleCreated) return;
if (InvokeRequired)
{
try
{
Invoke(new MyUpdateCallback(this.MyUpdate), e.MyData);
}
catch (InvalidOperationException ex) // pump died before we were processed
{
if (this.IsHandleCreated) throw; // not the droids we are looking for
}
}
else
{
this.MyUpdate(e.MyData);
}
}
// the update function
void MyUpdate(Object myData)
{
...
}
The exception filtering can be tailored to suit whatever the needs are. Its good to be aware that worker threads often dont have all the cushy outer exception handling and logging the UI threads do, in most applicaitons, so you may wish to just gobble up any exception on the worker side. Or log and rethrow all of them. For many, uncaught exceptions on worker thread means the app is going to crash.
Try using
if(!myControl.Disposing)
; // invoke here
I had the exact same problem as you. Ever since I switched to checking .Disposing on the control, the ObjectDisposedException has gone away. Not saying this will fix it 100% of the time, just 99% ;) There is still a chance of a race condition between the check to Disposing and the call to invoke, but in the testing I've done I haven't ran into it (I use the ThreadPool and a worker thread).
Here's what I use before each call to invoke:
private bool IsControlValid(Control myControl)
{
if (myControl == null) return false;
if (myControl.IsDisposed) return false;
if (myControl.Disposing) return false;
if (!myControl.IsHandleCreated) return false;
if (AbortThread) return false; // the signal to the thread to stop processing
return true;
}
may be lock(mImageListView){...} ?
You could use mutexes.
Somewhere at the start of the thread :
Mutex m=new Mutex();
Then :
if (mImageListView != null &&
mImageListView.IsHandleCreated &&
!mImageListView.IsDisposed)
{
m.WaitOne();
if (mImageListView.InvokeRequired)
mImageListView.Invoke(
new RefreshDelegateInternal(mImageListView.RefreshInternal));
else
mImageListView.RefreshInternal();
m.ReleaseMutex();
}
And whereever it is you are disposing of mImageListView :
m.WaitOne();
mImageListView.Dispose();
m.ReleaseMutex();
This should ensure you cant dispose and invoke at the same time.
See also this question:
Avoiding the woes of Invoke/BeginInvoke in cross-thread WinForm event handling?
The utility class that resulted EventHandlerForControl can solve this problem for event method signatures. You could adapt this class or review the logic therein to solve the issue.
The real problem here is that nobugz is correct as he points out that the APIs given for cross-thread calls in winforms are inherently not thread safe. Even within the calls to InvokeRequired and Invoke/BeginInvoke themselves there are several race conditions that can cause unexpected behavior.
If a BackGroundWorker is a possibility, there's a very simple way to circumvent this:
public partial class MyForm : Form
{
private void InvokeViaBgw(Action action)
{
BGW.ReportProgress(0, action);
}
private void BGW_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (this.IsDisposed) return; //You are on the UI thread now, so no race condition
var action = (Action)e.UserState;
action();
}
private private void BGW_DoWork(object sender, DoWorkEventArgs e)
{
//Sample usage:
this.InvokeViaBgw(() => MyTextBox.Text = "Foo");
}
}
Handle the Form closing event. Check to see if your off UI thread work is still happening, if so start to bring it down, cancel the closing event and then reschedule the close using BeginInvoke on the form control.
private void Form_FormClosing(object sender, FormClosingEventArgs e)
{
if (service.IsRunning)
{
service.Exit();
e.Cancel = true;
this.BeginInvoke(new Action(() => { this.Close(); }));
}
}
The solution proposed by Isak Savo
try
{
myForm.Invoke(myForm.myDelegate, new Object[] { message });
}
catch (ObjectDisposedException)
{ //catch exception if the owner window is already closed
}
works in C# 4.0 but for some reasons it fails in C#3.0 (the exception is raised anyway)
So I used another solution based on a flag indicating if the form is closing and consequently preventing the use of invoke if the flag is set
public partial class Form1 : Form
{
bool _closing;
public bool closing { get { return _closing; } }
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
_closing = true;
}
...
// part executing in another thread:
if (_owner.closing == false)
{ // the invoke is skipped if the form is closing
myForm.Invoke(myForm.myDelegate, new Object[] { message });
}
This has the advantage of completely avoiding the use of try/catch.
One way might be to call the method itself ones more instead of invoking the ImageListView-Method:
if (mImageListView != null &&
mImageListView.IsHandleCreated &&
!mImageListView.IsDisposed)
{
if (mImageListView.InvokeRequired)
mImageListView.Invoke(new YourDelegate(thisMethod));
else
mImageListView.RefreshInternal();
}
That way it would check one more time before finally calling RefreshInternal().
The suggestion to stop the thread generating the messages is not acceptable. Delegates can be multicast. Because one listener does not want to listen to the band, you don't shoot the band members.
Since the framework doesn't provide any easy way I know of to clear the message pump of those event messages, and since the form does not expose its private property that lets us know the form is closing:
Set a flag on the IsClosing Event of the window after you unsubscribe or stop listening to the events, and always check this flag before you do a this.Invoke().
i have same error. my error occurred in thread. finally i write this method :
public bool IsDisposed(Control ctrl)
{
if (ctrl.IsDisposed)
return true;
try
{
ctrl.Invoke(new Action(() => { }));
return false;
}
catch (ObjectDisposedException)
{
return true;
}
}
This works for me
if (this.IsHandleCreated){
Task.Delay(500).ContinueWith(_ =>{
this.Invoke(fm2);
});
} else {
this.Refresh();
}