I wonder is there a better way to implement this "simple lock" - c#

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;
}
});
}

Related

Monitor.Exit throws SynchronizationLockException

So, I have been getting this error for a bit now and I performed a few tests, but I cannot figure out the problem. I get a System.Threading.SynchronizationException when calling Monitor.Exit(). First, I created a wrapper for all Monitor methods I use that prints "Locked" and "Unlocked" to the screen. This prints out fine and right before my call to Exit, it says the lock is LOCKED. When I call exit it throws the error and FAILS to unlock my object. This is obvious and visible from my UI. It says something about can't execute from a non-synchronous block?
Note: My Monitor.Exit command is called in a different method call then my Monitor.Enter command. It is still safe, but could this be the issue?
EDIT: Background Info: I am implementing a Mario like game. When Mario goes into Transition my group wants all of our various Timers to stop updating (block their threads) and just do a specific update to our player. All the Timer threads already have a common lock being used called TimerLock. Here is the sample code for this transition.
public void Begin()
{
if (Monitor.TryEnter(ManagedTimer.Lock,100))
{
try
{
//Turn off updating for all objects
TurnOffPhysicsUpdate(); //Psuedocode for this...
//Create timer till end event
EndTimer = new System.Timers.Timer(600.00);
EndTimer.AutoReset = false;
EndTimer.Elapsed += EndTimer_Elapsed;
EndTimer.Enabled = true;
EndTimer.Start();
//Create swap timer
SwapTimer = new System.Timers.Timer(25.0);
SwapTimer.AutoReset = false;
SwapTimer.Elapsed += SwapTimer_Elapsed;
SwapTimer.Enabled = true;
SwapTimer.Start();
}
catch (Exception e)
{
EndFreeze();
Debug.WriteLine("Failed to setup transition: " + e.Message);
}
}
}
private void SwapTimer_Elapsed(object sender, ElapsedEventArgs e)
{
SwapTimer.Stop();
//Transition Mario State....
SwapTimer.Start();
}
private void EndTimer_Elapsed(object sender, ElapsedEventArgs e)
{
EndFreeze();
}
private void EndFreeze()
{
try
{
SwapTimer.Stop();
EndTimer.Stop();
TurnOnPhysicsUpdate(); //psuedocode
//Ensure Mario ends in the proper state
user.StateMachine.TransitionSizeState(newState);
}
catch (Exception e)
{
Debug.WriteLine("FATAL ERROR: " + e.Message);
}
finally
{
//Exception occurs here!!!!!!!!!!!!!
Monitor.Exit(ManagedTimer.Lock,"TimerLock");
}
}
When your EndTimer_Elapsed method is called by the timer, you are not in the same thread that owns the lock, so you are not permitted to release the lock there.
This is a good example of why one should just avoid using Monitor.Enter/Exit altogether. It's pretty tricky for even an expert in concurrent programming to get everything just right, and it's a minefield for anyone else. If you stick with using Monitor via the lock statement, it becomes a lot harder to make this kind of mistake. :)
Finally note that it's not really clear from your example why you are using this lock. You might consider posting a different question explaining the synchronization issue you're trying to solve, so that you can get help designing the code correctly and without Monitor.Enter/Exit

Why Is This ThreadPool.QueueUserWorkItem Code Not Failing My Test?

The code in question
public void StartPlaying()
{
ThreadPool.QueueUserWorkItem(ignoredState =>
{
while (_playlist.Count > 0)
{
var audioFile = _playlist.Dequeue();
if (StartedPlaying != null)
StartedPlaying(this, new TypedAudioFileEventArgs(audioFile));
audioFile.SoundPlayer.PlaySync();
audioFile.SoundPlayer.Dispose();
if (StoppedPlaying != null)
StoppedPlaying(this, new TypedAudioFileEventArgs(audioFile));
}
});
}
and my test:
[TestMethod()]
public void StartPlayIsCalledTwice_OnlyRunningOnce()
{
int timeBetweenPlays = 0;
var target = new TypedAudioFilePlayer(timeBetweenPlays);
target.AddFile(TypedAudioFileCreator.CreateWord(1, "bl"));
target.StartedPlaying += StartedPlaying_Once;
target.StartPlaying();
target.StartPlaying();
}
private bool _once = false;
private void StartedPlaying_Once(object sender, TypedAudioFileEventArgs e)
{
if (!_once)
_once = true;
else
Assert.Fail("Should not be called more than once!");
}
I believe my unit test should fail, judging by the MSDN description of ThreadPool.QueueUserWorkItem:
Queues a method for execution. The method executes when a thread pool thread becomes available.
The default ThreadPool size is 512, so two threads should immediately be available to process the StartPlaying call. I believe my code should fail since I haven't provided any safeguards from race conditions in which both threads can access the same resource.
What's happening here?
Because the StartedPlaying event is only raised if StartPlaying is called when there are items to play.
_playlist.Dequeue(); dequeues the file you enqueue. Therefore the second time you get to while (_playlist.Count > 0) it will immediately fail, passing the second call to StartPlaying straight through without raising the event.
Also, as Bruno Silva points out, the thread spawned by the second call to StartPlaying may not have a chance to execute anything before the test exits.
For what it's worth, there are about a million at least 2 threading mistakes in this code also:
// Where did _playlist come from? Is it shared state among the player threads?
// If so, all access to it should be in locks, since queues are not thread safe
while (_playlist.Count > 0)
// Both of these start threads and then immediately return.
// The test will probably exit before either of those threads do anything much
target.StartPlaying();
target.StartPlaying();
}
If you want to properly unit test, you need to define preconditions, expectations, actions, and postconditions:
Preconditions: you have an initialized TypedAudioFilePlayer with one file queued:
var target = new TypedAudioFilePlayer(timeBetweenPlays);
target.AddFile(TypedAudioFileCreator.CreateWord(1, "bl"));
Expectations: The StartedPlaying event will be raised only once if StartPlaying is called twice
target.StartedPlaying += StartedPlaying_Once;
Actions: The StartPlaying method will be called twice:
target.StartPlaying();
target.StartPlaying();
Postconditions: The StartedPlaying event was only raised once:
private bool _once = false;
private void StartedPlaying_Once(object sender, TypedAudioFileEventArgs e)
{
if (!_once)
_once = true;
else
Assert.Fail("Should not be called more than once!");
}
Now, your test succeeds. That's not good in this case, because of what I explain above. You need to get your test to a failing state by eliminating the queue bug and race condition, then work on making the test pass the right way.
It seems that you are working with a shared resource between two threads so once might not be set to true when the Play is called for the second time. You can use a lock to allow executing part of your code by one thread at a time :
private readonly object lock_object=new object();
private void StartedPlaying_Once(object sender, TypedAudioFileEventArgs e)
{
lock(lock_object)
{
if (!_once)
_once = true;
else
Assert.Fail("Should not be called more than once!");
}
}
Could those be failing outside the text execution? Your test ends right after you queue the item so I'm not sure what is happening to those threads when the test method ends its execution. Have you tried using WaitHandle to wait for the them to finish inside the test?
See http://msdn.microsoft.com/en-us/library/system.threading.waithandle.aspx for an example.

Is it OK to use Monitor.TryEnter in event handler method?

I have EventHandler method which is called pretty often and it's body processing takes some time. Is it OK, to lock operations inside this handler it via Monitor?
The purpose is that meanwhile locker locks the object other events and processing of the object are simply skipped.
public void MyEventHandler(object sender, EventArgs e)
{
if (!Monitor.TryEnter(locker)) return; // skipping meanwhile processing
// do some stuff here
Monitor.Exit(locker)
}
it looks like it would be cleaner/more performant to
(a) prevent the events from being raised
(b) use a condition variable.
Regardless, always put the Monitor.Exit into a finally block
It's not horrible, as long as:
You're doing this on a background thread (or, to the point, you're not doing this on the event handling thread).
You're synchronizing all access to whatever your //do some stuff code needs.
You wrap everything after the TryEnter in a try/finally, like so:
.
public void MyEventHandler(object sender, EventArgs e)
{
if (!Monitor.TryEnter(locker)) return;
try
{
// do some stuff here
}
finally
{
Monitor.Exit(locker);
}
}
It'd be nicer if you could prevent firing the event at all (and thus avoid starting a thread to potentially do nothing -- cause of course you're not doing this time-consuming processing on the event handling thread...)
Alternatively, if you don't really need to lock for the whole duration (that is, if the event handler won't be doing anything that requires synchronization with other code), you could lock just long enough to set a flag, like
private Object condition_lock = new Object();
private bool handlingEvent = false;
public void MyEventHandler(object sender, EventArgs e)
{
lock (condition_lock)
{
if (handlingEvent) return;
handlingEvent = true;
}
try
{
// do some stuff here
}
finally
{
handlingEvent = false;
}
}

How to respond events while a threaded operation is running in .NET

I have a class to launch background operations in a WinForms application. I need to write this background worker since my requisites are using .NET 1.1, so I cannot use BackgroundWorker, that is only available from .NET 2.0
This class get a delegate and execute it in a thread. I want the main thread to respond to events.
I also want to indicate that the operation is running setting the application cursor to Cursors.WaitCursor.
What do you think about current implementation? I'm interested in the method WaitTillThreadFinishes(), because I'm not sure about Application.DoEvents(), please read the code and share with me opinions about WaitTillThreadFinishes.
The following code executes the operation:
private object ExecuteOperation (Delegate target, params object[] parameters)
{
mTargetDelegate = target;
mTargetParameters = parameters;
mTargetThread = new Thread(new ThreadStart(ThreadProc));
mTargetThread.Name = mTargetDelegate.Method.Name;
mOperationFinished = false;
// start threaded operation
mTargetThread.Start();
// perform active waiting
WaitTillThreadFinishes();
return mTargetResult;
}
The following code is executed in a thread, simply call the delegate, and wrap exceptions:
protected virtual void ThreadProc()
{
try
{
mTargetResult = mTargetDelegate.DynamicInvoke(mTargetParameters);
}
catch (ThreadAbortException) { }
catch (Exception ex)
{
//manage exceptions here ...
}
finally
{
mOperationFinished = true;
}
}
And this is the code performs an active waiting. I'm interested on share with you. Any better option? Any pain calling Application.DoEvents() massively?
private void WaitTillThreadFinishes ()
{
// Active wait to respond to events with a WaitCursor
while (!mOperationFinished)
{
// sleep to avoid CPU usage
System.Threading.Thread.Sleep(100);
Application.DoEvents();
Cursor.Current = Cursors.WaitCursor;
}
Cursor.Current = Cursors.Default;
}
Thanks in advance.
Please let me know if i understood your question correctly.
Why dont you use an event to notify the UI that the worker finished his job?
This way, the UI doen't get blocked by the worker, and you avoid busy waiting.
Sample Implementation
public class MyBackgroundWorker
{
// Fields
private Delegate _target;
private object[] _arguments;
// Events
public event EventHandler RunWorkerStarted;
public event EventHandler<RunWorkerCompletedEventArgs> RunWorkerCompleted;
// Event Invocators
public void InvokeRunWorkerStarted()
{
var handler = RunWorkerStarted;
if (handler != null) handler(this, new EventArgs());
}
public void InvokeRunWorkerCompleted(object result)
{
var handler = RunWorkerCompleted;
if (handler != null) handler(this, new RunWorkerCompletedEventArgs(result));
}
public void RunWorkerAsync(Delegate target, params object[] arguments)
{
_target = target;
_arguments = arguments;
new Thread(DoWork).Start(arguments);
}
// Helper method to run the target delegate
private void DoWork(object obj)
{
_target.DynamicInvoke(_arguments);
// Retrieve the target delegate's result and invoke the RunWorkerCompleted event with it (for simplicity, I'm sending null)
InvokeRunWorkerCompleted(null);
}
}
internal class RunWorkerCompletedEventArgs : EventArgs
{
public RunWorkerCompletedEventArgs(object result)
{
Result = result;
}
public object Result { get; set; }
}
Usage
In the UI you can use it this way:
private void button1_Click(object sender, EventArgs e)
{
var worker = new MyBackgroundWorker();
worker.RunWorkerStarted += worker_RunWorkerStarted;
worker.RunWorkerCompleted += worker_Completed;
worker.RunWorkerAsync(new MethodInvoker(SomeLengthyOperation), null);
}
void worker_RunWorkerStarted(object sender, EventArgs e)
{
}
void worker_Completed(object sender, EventArgs e)
{
MessageBox.Show("Worker completed");
}
private void SomeLengthyOperation()
{
Thread.Sleep(5000);
}
Final Notes
Remember to Invoke() in the event handlers to access the UI thread correctly. You can also modify the worker so this is done in a safe way.
There isn't much support in 1.1 for doing this, but I'll tell you what I'd do (sorry, no code at this time).
As for the asynchronous operation, I'd use the APM to kick off and complete the asynchronous method. This is fully supported in 1.1, so no worries there.
The idea is that in the UI, you store some indication that work is being done (a boolean field, for example) and (optionally) a Timer used to "wake up" the UI on a regular basis to check on the current status of the background work and indicate this to the user.
You would set the boolean to indicate you are working in the background, call BeginInvoke() on your delegate (using the overload that takes a callback search for "Executing a Callback Method When an Asynchronous Call Completes
"), and start the Timer. When the user attempts to use the UI, you would optionally check the boolean and cancel the operation, thus preventing the user from doing something harmful while you are waiting. When the timer Ticks, you can check the status of your asynchronous method by, say, a shared field that the method writes updates to and the UI reads. For example, a double which the UI uses to update a progress bar.
Once the callback fires, you clean up your asynchronous mess (i.e., call EndInvoke, and handle any exceptions thrown, etc), turn off the Timer and reset your boolean running indication field.
By using this method, you can keep the UI completely responsive (and partially usable, depending on your overall design), can set up a mechanism to abort the background worker (through the use of another field, the reverse of the boolean mentioned earlier, and inform the user of the status of the operation.
There is occasionally a case for kicking off a thread and waiting for its return, if you are doing other things in the meantime, but in this case, with the code you have shown, it is meaningless.
If you want the threadProc to allow for events to be processed, then call doevents in that, which will free up the CPU briefly, allowing for processing.
Unless you have a particular reason for needing to thread processes, you should not do it. Getting it right - as Ian Boyd has said - is difficult, and the more you need to interact with it the harder it is. If you can run fire-and-forget threads, that is the easiest.
Ideally you start the asynchronous operation and leave your form alone (aside from maybe using the Cursors.AppStarting cursor).
When your threaded operation completes, it then needs to fire some sort of BackgroundOperationComplete event. This is where your would call from your asynchronous delegate code:
form.Invoke(BackgroundOperationComplete);
The form's BackgroundOperationComplete method is where you can handle the fact that the background operation is complete:
void BackgroundOperationComplete()
{
this.Cursor = Cursors.DefaultCursor;
lblAnswer.Text = "The thread is done";
}
If all else fails, keep the operation synchronous, and use an IProgressDialog. (brief conceptual pseudo-code from memory):
void DoStuff()
{
IProgressDialog pd = new ProgressDialog();
pd.SetTitle = "Calculating Widgets";
pd.StartTimer(PDTIMER_RESET, NULL)
pd.StartProgressDialog(this.Handle, NULL, PROGDLG_MODAL | PROGDLG_NOTIME | PROGDLG_NOPROGRESSBAR | PROGDLG_NOCANCEL, NULL);
try
{
pd.SetLine(1, "Please wait while the widgets are frobbed");
DoTheThingThatDoesTheSynchronousStuff();
}
finally
{
pd.StopProgressDialog();
}
pd = null;
}

Avoid calling Invoke when the control is disposed

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();
}

Categories

Resources