Related
I need some help. I started c# and not very familiar with event handling and threading yet. As a beginner and as time and exposure progresses, I would like to learn more on these advanced topics and improved and hope all of you here can help me.
I ran onto this problem of "Cross-thread operation not valid: Control 'textbox control called stackStatus' accessed from a thread other than the thread it was created on". I have tried to troubleshoot this whole day but simply no avail. I am stuck. :-( The program hits an exception and cannot continue to execute smoothly.
I have read the following threads and tried a few things but I guess I am still missing something. Appreciate if someone can help me out here. Thanks.
Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on
Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on
Here's are most of the portion of the code:
private void createCloud_Click(object sender, EventArgs e)
{
CreateCloud(); //start creation method
stackStatus.Text = "Creating stack..."; //updates the cloud status textbox
stackStatus.Refresh();
Cursor.Current = Cursors.WaitCursor; //change the cursor to wait state
Start_Describestack(); //call describe method to find out the status of cloud creation progress
Task.Delay(12000); // wait 12s in case not ready
Start_Describestack(); // call again describe method to find out the cloud creation progress status
Cursor.Current = Cursors.Default; //put cursor on wait
describeevents(); // call method to get all cloud creation event data and publish on the datagridview
}
private void Start_Describestack()
{
//method making use of timer to call
_timer = new System.Timers.Timer(15000);
_timer.Elapsed += new ElapsedEventHandler(describeStack);
_timer.Enabled = true;
}
delegate void describeStackCallBack(object sender, ElapsedEventArgs e);
private void describeStack(object sender, ElapsedEventArgs e)
{
//this method makes api calls through cloudclient to describe the stack
//this is where the "Cross-thread operation not valid: Control 'stackStatus' accessed from a thread other than the thread it was created on"
var client = new cloudclient();
var request2 = new StacksRequest();
request2.Cloudstackname = stackid;
try
{
var response = client.DescribeCloudStacks(request2);
foreach (var stack in response.Stacks)
{
//something is wrong here but I do not know how to fix it. Please help
if (this.stackStatus.InvokeRequired)
{
describeStackCallBack d = new describeStackCallBack(describeStack);
this.Invoke(d, new object[] { sender, e });
stackStatus.Refresh();
describevents();
}
else
{
stackStatus.Text = stack.StackStatus;
stackStatus.Refresh();
describeevents();
}
}
}
catch (Exception)
{
if (this.stackStatus.InvokeRequired)
{
describeStackCallBack d = new describeStackCallBack(describeStack);
this.Invoke(d, new object[] { sender, e });
stackStatus.Text = "Stack not found/Deleted";
}
else
{ stackStatus.Text = "Stack not found/Deleted"; }
}
describeevents();
}
private void describeevents()
{
var newclient = new cloudclient();
var request3 = new eventrequest();
request3.Cloudstackname = stackid;
try
{
var response = newclient.eventstack(request3);
dataGridView3.Rows.Clear();
foreach (var events in response.sevents)
{
dataGridView3.Rows.Add(events.Timestamp, events.ResourceStatus, events.ResourceType);
}
}
catch (Exception)
{
dataGridView3.Rows.Clear();
MessageBox.Show("Stack not ready!");
}
dataGridView3.Refresh();
}
Rather than doing :
stackStatus.Text = "some text";
Try :
stackStatus.Invoke((Action)delegate
{
stackStatus.Text = "some text";
});
Note that GUI element assignment outside the thread or they are declared is deprecated because the controls may no longer be available at any time.
There are two issues in your approach, which conspire to prevent your attempt to imitate the solution to the exception from working:
You have failed to note that the proposed solution calls itself, and in so doing, causes the foreach to be restarted for each time it's invoked from the worker thread.
You are following Microsoft canonical implementation of cross-thread-friendly Invoke()-based code, which IMHO is lame.
It is my opinion that there is no point in ever checking InvokeRequired. The standard pattern always involves situations where on the first entry, you know you will require Invoke(), and even if you didn't, there's no real harm in calling Invoke() when it's not necessary.
Instead, you should always keep separate the code that should run in the UI thread, and the code that does not. Then, in the code that does not, always use Invoke() to execute the code that does.
For example:
private void Start_Describestack()
{
//method making use of timer to call
_timer = new System.Timers.Timer(15000);
_timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);
_timer.Enabled = true;
}
private void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
Invoke((MethodInvoker)describeStack);
}
private void describeStack()
{
var client = new cloudclient();
var request2 = new StacksRequest();
request2.Cloudstackname = stackid;
try
{
var response = client.DescribeCloudStacks(request2);
foreach (var stack in response.Stacks)
{
stackStatus.Text = stack.StackStatus;
stackStatus.Refresh();
describeevents();
}
}
catch (Exception)
{
stackStatus.Text = "Stack not found/Deleted";
}
describeevents();
}
That said, an improvement on the above would be to use System.Windows.Forms.Timer instead of System.Timers.Timer. The latter raises the Elapsed event on a worker thread, but the former raises its event on the UI thread, right where you want it. No Invoke() required at all.
You have at least one other problem with your code as well:
private void createCloud_Click(object sender, EventArgs e)
{
CreateCloud(); //start creation method
stackStatus.Text = "Creating stack..."; //updates the cloud status textbox
stackStatus.Refresh();
Cursor.Current = Cursors.WaitCursor; //change the cursor to wait state
Start_Describestack(); //call describe method to find out the status of cloud creation progress
Task.Delay(12000); // wait 12s in case not ready
Start_Describestack(); // call again describe method to find out the cloud creation progress status
Cursor.Current = Cursors.Default; //put cursor on wait
describeevents(); // call method to get all cloud creation event data and publish on the datagridview
}
In the above, the call to Task.Delay(12000); accomplishes nothing. The Task.Delay() method doesn't actually block the current thread. Instead, it returns an awaitable task object. The code in which it appears only is delayed if you wait on the returned object.
It's also questionable to call Start_Describestack() twice, because this method doesn't do anything except start the timer. Calling it twice means now you have two timers running.
Finally, you should also not have all those calls to Refresh() in your code. Correctly written Windows Forms code will not need anything like that. Updates to control properties will cause control invalidation automatically, and the control will update as needed at its next opportunity, which as long as the code is written correctly, will be soon enough for the user to not notice any significant delay.
Now, putting all of the above together, it seems to me that you should avoid using the timer altogether. There is still the potential problem that your call to DescribeCloudStacks() is a lengthy one, and could cause the UI to momentarily appear "stuck", which obviously isn't a desirable thing. In addition, the timer-based code, whether you require Invoke() or not, can be harder to understand, especially for someone new to asynchronous programming and threading.
Using the async/await feature, you can write the code in a conventional, procedural way, while still ensuring that the UI remains responsive, and that the UI-related code is always executed in the UI thread where it belongs. That might look something like this:
private async void createCloud_Click(object sender, EventArgs e)
{
CreateCloud(); //start creation method
stackStatus.Text = "Creating stack..."; //updates the cloud status textbox
Cursor.Current = Cursors.WaitCursor; //change the cursor to wait state
await describeStack(); //call describe method to find out the status of cloud creation progress
await Task.Delay(12000); // wait 12s in case not ready
await describeStack(); // call again describe method to find out the cloud creation progress status
Cursor.Current = Cursors.Default; //put cursor on wait
describeevents(); // call method to get all cloud creation event data and publish on the datagridview
}
private async Task describeStack()
{
var client = new cloudclient();
var request2 = new StacksRequest();
request2.Cloudstackname = stackid;
try
{
var response = await Task.Run(() => client.DescribeCloudStacks(request2));
foreach (var stack in response.Stacks)
{
stackStatus.Text = stack.StackStatus;
describeevents();
}
}
catch (Exception)
{
stackStatus.Text = "Stack not found/Deleted";
}
describeevents();
}
The above executes most of the describeStacks() method in the UI thread. The exception would be the DescribeCloudStacks() method call, which is run as a worker task. While it's running, the UI thread is free to operate normally. Execution of the describeStacks() method is temporarily put "on hold" (without blocking the UI thread) while the worker task runs, and then is resumed when it completes.
It's not clear from your original example whether you really wanted a repeating timer or not. The above doesn't use any loops; it calls the describeStack() method only twice, with a 12-second delay in between. But if you want a loop, you can do that as well. Just use the await Task.Delay() for the delay and await describeStack() for the operation, and put that in a loop as you like.
I don't see where the stackStatus object is created so I'm just guessing that you are creating it through a contructor for the class containing describeStack() and then you are registering an event handler for the click. I think what is happening is the event handler is being run on a different thread from the one in which the instance was created so you might have to change how you create the stackStatus object. That error is likely happening because whatever type the stackStatus was created from is known to not be reentrant so when the runtime detects access between threads it raises an exception so you are aware and can either prevent or recover from race-conditions or deadlocks.
I am running a while loop which keeps track of some events forever, In case if i get any exception i am changing its reference to null hoping that the current thread will be aborted and the new reference of that thread will be created. Is it correct or any better way to abort the current thread and start a newer one.
I am trying to do this:
Thread th;
Main()
{
th = new thread(myfunction);
th.Start();
}
void myfunction()
{
while(true)
{
try
{
// something interesting here.
}
catch(exception)
{
th = null;
}
}
}
Only thing that will happen is that Thread will remain inaccessible from the Enclosing class.
If there are no further processing, doing so will make the thread out of reach from GC appllication roots. This makes object available for garbage collection in next GC trigger.
You need to do:
return;
instead of:
th = null;
Because the thread will keep on running. The thread object will not get collected, since it will stay referenced as long as the code is running.
Clean up anything you need to for that thread, then break out of the while loop like this:
void runningOnThread()
{
while (true)
{
try
{
//...
}
catch (Exception e)
{
break;
}
}
//thread cleanup code goes here, if you have any.
}
It would be a good idea to log the exception when you catch it. That way you know when you've hit an exception.
First, if you run into an exception, before worrying about starting a new thread, be sure that you actually handle the exception and ensure that the restarted thread will be able to run successfully. Otherwise, you're just going to get a constant stream of crashing threads, and a choppy program while it handles the exception parade. Just some food for thought.
Now, answering the question, best case nulling the reference to the thread will just leave you in an infinite loop, worst case you try to use 'th' later and you get an exception because it's null. Nulling the reference to the thread won't somehow make it aware that it needs to restart itself any more than nulling a reference to parameter you gave it as a function argument will. If you absolutely need some kind of ability to abort/restart the thread, look into doing one of:
raising an event when the thread crashes and break out of the while loop, or
setting a boolean/enum flag saying what the thread is doing, and have the main thread check on it every so often to make sure it hasn't been set to the error state.
This is code is completely off the top of my head, isn't that good, but will give you the general idea:
delegate void ThreadCrashedEvent();
Event ThreadCrashedEvent threadCrashed;
Thread th;
Main()
{
threadCrashed += OnThreadCrashed();
th = new thread(myfunction);
th.Start();
}
void OnThreadCrashed()
{
th = new thread(myfunction);
th.Start();
}
void myfunction()
{
while(true)
{
try
{
LetsGetDangerous();
}
catch(exception)
{
if(threadCrashed != null)
{
threadCrashed();
return;
}
}
}
Is there a better way to do implement a simple lock like below?
I only want to to the "DOSOMETHING" if it's not already being run. Should I be using reall locks here? if I use lock will that cause everything to queue up and wait for the lock to release? (that's not what I want!)
Thanks
bool running = false;
void DataDisplayView_Paint(object sender, PaintEventArgs e)
{
// if (!this.initialSetDone)
if (!running)
{
this.running = true;
//DOSOMETHING
this.running = false;
}
}
No, you do not want to use locks here. This is not a thread synchronization problem. This is a method reentrancy problem.
You might try something like this.
bool running = false;
void DataDisplayView_Paint(object sender, PaintEventArgs e)
{
if (!this.running)
{
this.running = true;
try
{
//DOSOMETHING
}
finally
{
this.running = false;
}
}
}
You just need to synchronise (lock is the simplest way) bits of the code:
bool running = false;
readonly object padlock = new object();
void DataDisplayView_Paint(object sender, PaintEventArgs e)
{
if (!this.initialSetDone)
{
lock(padlock)
{
if(running) return;
running = true;
}
try {
//DOSOMETHING
}
finally
{
lock(padlock)
{
this.running = false;
}
}
}
}
The best way is to use a try/finally block
try {
this.running = true;
...
} finally {
this.running = false;
}
Real thread locks are only needed if this method is called from multiple threads. Given that it appears to be a paint event handler this is unlikely as controls are affinitized to a single thread.
Am I missing something? The code as you've posted it does not seem to do anything. That is, the code will run whether or not running is true.
Generally, any code that tries to "lock" itself like this...
if (!running)
{
running = true;
try
{
// This code should not call itself recursively.
// However, it may execute simultaneously on more than one thread
// in very rare cases.
}
finally
{
running = false;
}
}
...is perfectly good, as long as you're in a single-threaded scenario. If you're running multi-threaded code, problems can arise because you are assuming that no two threads will reach the if (!running) line at the same time.
The solution in multi-threaded code is to use some form of atomic switch. I've used the AutoResetEvent for this purpose:
var ready = new AutoResetEvent(true);
if (ready.WaitOne(0))
{
try
{
// This code will never be running on more than one thread
// at a time.
}
finally
{
ready.Set();
}
}
Note that if you're having reentrancy on your paint callback, you've got a more serious problem. Paint handlers should be blocking your message pump (and should complete relatively quickly), so you should never see this case. The only exception is if you call Application.DoEvents() from somewhere in your paint handler, which you really shouldn't be doing.
You shift varaible names in the middle, so I'm going to assume you wanted:
bool running = false;
void DataDisplayView_Paint(object sender, PaintEventArgs e)
{
if (!this.running)
{
this.running = true;
//DOSOMETHING
this.running = false;
}
}
The problem you have here is that if DataDisplayView_Paint can be called from multiple threads, then it is possible that between the if (!this.running) and the this.running = true; the other thread could jump in and start DOSOMETHING (because running is still false). Then the first thread will resume, and start DOSOMETHING again. If that is a possiblity, then you will need to use a real lock.
If you use Monitor.TryEnter instead you could specify a timeout, in which case the result you get is such that:
only one thread can run the DOSOMETHING at a time
subsequent calls will try to get the lock and give up after the timeout clause
If you don't provide with a timeout, or set the timeout to 0, this call won't block and will return immediately (maybe that'd suit your requirement better?):
if (!this.initialSetDone && Monitor.TryEnter(_lock))
{
// DOSOMETHING
}
Alternatively, you can make the running variable volatile so that you will always get the latest value stored in the variable:
private volatile bool running;
if (!this.initialSetDone && !this.running) // #1
{
this.running = true;
try
{
// DOSOMETHING
}
finally
{
this.running = false;
}
}
The second approach won't queue up subsequent calls, but there is the possibility that two threads will both hit #1 and evaluate that it's safe to proceed then both end up running DOSOMETHING, though it's highly unlikely.
I only want to to the "DOSOMETHING" if
it's not already being run
Your question doesn't have enough information, so I can't help but make assumptions about your code.
My first assumption is that, based on the signature DataDisplayView_Paint(object s, PaintEventArgs e), your code runs on the GUI thread.
My second assumption is that your code DOSOMETHING is synchronous.
With that in mind, here's version of your code which guarantees we only run DOSOMETHING if its not already being run:
void DataDisplayView_Paint(object s, PaintEventArgs e)
{
//DOSOMETHING
}
The GUI thread will only process one message at a time, and your DataDisplayView_Paint method does not exit until DOSOMETHING completes. If you're doing anything with the GUI like drawing to a Graphics object or changing labels, then this code won't get invoked from more than one thread -- and if it does, .NET will throw an exception. In other words, you don't need any synchronization.
Let's assume DOSOMETHING runs asyncronously -- now we have an interesting problem, but its very easy to solve, and you don't need any bools.
Essentially, all you're doing is disabling your event handler while DOSOMETHING runs, then re-enabling it. Instead of using a bool, unhook and rehook your event handler as needed:
void DataDisplayView_Paint(object s, PaintEventArgs e)
{
DataDisplayView.Paint -= DataDisplayView_Paint;
DoSomethingAsynchronously(); // re-hooks event handler when completed
}
void DoSomethingAsychronously()
{
ThreadPool.QueueUserWorkItem(() =>
{
try
{
// DOSOMETHING
}
finally
{
// may need a lock around this statement
DataDisplayView.Paint += DataDisplayView_Paint;
}
});
}
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();
}
I am trying to build a small application that logins into a server and gathers data from it constantly. The problem that I am having is that my GUI is slow to respond even when using either background worker or a thread. When my application tries to login into the server, I see "(Not Responding)" appear in my login form, but it logins in few seconds later without Windows giving the "The program has stopped responding... terminate application" dialog. When I click the start button on my application I noticed by GUI becomes very sluggish and unresponsive. I was wondering how I could improve the response time of my program. Here is the code for the Login form using a background worker and the code for my thread that gathers data from the server. I apologize for the last section of the code not being format correctly, but SO is being non-cooperative.
private void btnLogin_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(txtAccount.Text) || string.IsNullOrEmpty(txtPassword.Text))
{
MessageBox.Show("Must Enter Username and Password");
return;
}
btnLogin.Enabled = false;
account = txtAccount.Text;
password = txtPassword.Text;
accountType = cmbAccountType.SelectedItem.ToString();
loginBackgroundWorker.RunWorkerAsync();
}
private void loginBackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
loginSuccess=tradingDesk.Login(account, password, accountType);
}
private void loginBackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (loginSuccess)
{
this.DialogResult = DialogResult.OK;
}
btnLogin.Enabled = true;
}
private void btnStart_Click(object sender, EventArgs e)
{
Thread dataThread=new Thread(GetServerData);
dataThread.IsBackground=true;
try
{
dataThread.Start();
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}}
private void GetServerData()
{
try
{
while (true)
{
lock (myLock)
{
//Perform Server Task with large amounts of data
}
}
}
catch
{
//Handle exception code
}
}
Try using BackgroundWorker for your processing - easier than handling threads yourself unless you're in the business of handling threads in a pool and you like that stuff (or you've been doing it like that since v1.0 as I have - you're just used to it that way).
I also put all my UI interactions into a background thread and marshall the calls back through to the UI thread. This article should help you out on both: Tools for Updating Windows Forms UI from Background Threads
Another test is to swap out your call to tradingDesk.Login with a simple sleep to see if that changes anything. And how's your CPU? Happen to notice if the thread or process spikes in CPU usage? Even a multi-threaded app that eats up all your CPU will stutter - Flash comes to mind - slows down my entire system even other processes.
Try setting Thread.Priority to something lower than the GUI.
Also, your thread is on the same cpu/core as the app (same process) so if it uses 100% then even with a lowered priority you might notice a difference.
There is a library I can't recall off the top of my head for parallel processing across cpus/cores - try that if priority doesn't fix it
This seems strange to me...:
private void btnStart_Click(object sender, EventArgs e)
{
Thread dataThread = new Thread(GetServerData); // Won't this go out of scope?
dataThread.IsBackground = true;
try
{
dataThread.Start(); // Isn't this asynchronous (i.e. doesn't block)?
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Seems to me that either dataThread.Start() is a blocking call, thus causing your UI thread to stall, or it's a non-blocking call, in which case the local reference dataThread goes out of scope almost immediately (presumably before the thread has had time to finish it's work)?
This is a perfect example of why ThreadPool exists. Please note, when you pass the delegate to the method you want threaded to the ThreadPool, the main UI thread (the one that drives the message pump) is free and clear, waiting for the next UI event. Unless you are communicating frequently with the UI thread, there should be no reason that the UI thread is bogged down to the point of becoming unresponsive.
private void btnStart_Click(object sender, EventArgs e)
{
// spawn the GetServerData() method on the ThreadPool
ThreadPool.QueueUserWorkItem(new WaitCallback(GetServerData));
// after the above is called, you'll immediately get here because
// the UI thread is free from having to process GetServerData()
return;
}
Note: WaitCallback delegate requires a single parameter of an object. Also, note the comment on the "lock" statement below.
private void GetServerData(object o)
{
try
{
while (true)
{
// if ANYTHING in the UI thread requires this lock (recurring timer),
// you've just eliminated ANY benefit to having this on a separate thread
lock (myLock)
{
// processor intensive code
}
}
}
catch
{
// handle exceptions
}
}