Trouble since 2005: InvalidOperationException and Kickout

R

Randolph Neall

Since we upgraded our solutions from VS 2003 to 2005, one user is repeatedly
reporting InvalidOperationExceptions, announced to her in the form of a
window that says "XXX.exe has encountered a problem and needs to close. We
are sorry for the inconvenience .... Please tell Microsoft about this
problem." --which I'm now doing.

The latest involved the following information:

EventType: clr20r3
P1: vmed.exe
P2: 1.0.2284.37257
P3: 4431cee3
P4: system.windows.forms
P5: 2.0.0.0
P6: 4333aefa
P7: 1508
P8: 17
P9: system.invalidoperationexception

We cannot reproduce this problem. If I ask the user to repeat the operation
the error does not recur on demand. Instead the problem seems random, now
popping up here and later popping up there.
Once the error definitely was not caused by reflection or invocation. Twice
it might have been. This problem is new to VS 2005. We use C#.

We have implemented a global exception handler, based on
application.threadexception event for handling uncaught exceptions, but that
handler is not getting called for these invalid operation exceptions.
Instead this apologetic Microsoft window pops up, whereupon the user is
summarily cast out.

What can we do to solve this problem or at least identify its cause?

Randy Neall
 
J

Jason Hales

Randy, I'm not sure if you've considered any of the following:

Are you using any multi-threading in your app? If so are you using
Invoke/InvokeRequired correctly?
I've found that those "hard-to-reproduce" bugs are often the result of
incorrect threads accessing a control.

There may also be a race condition happening -
InvalidOperationException is raised when a object is in the wrong state
such as calling Current before MoveNext on an Enumerator. Perhaps two
threads are trying to manipulate an object that is not inherently
thread safe.

Does your user have a dual processor PC? I spent days trying to track
a similar problem that was only manifesting itself on a user who's PC
was multi-processor.

In addition you might want to attach to the Domain.UnhandledException
event:
AppDomain.CurrentDomain.UnhandledException +=new
UnhandledExceptionEventHandler(CurrentDomain_UnhandledException)

It might be worth deploying the application's .PDB onto your user's PC
to get additonal debug info

Does the call stack give you any more usueful info?
 
R

Randolph Neall

Jason,

Thanks!

One question about deploying the .pdb: Do you also have to deploy the debug
versions of all the .dll's and exe's? Or are the dll's and exe's themselves
the same no matter how they are compiled? Does the mere presence of a .pdb
assure that one will get a line number in the exception?

We'll also try the app domain unhandled exception handler. Very good idea.

As far as call stack is concerned, the exception so far is not revealed to
the user with this information available. It's just that Microsoft window
with nothing beyond P1 to P9 values.

As I pointed out, this issue is new with VS 2005, and the one area in which
VS 2005 seems more touchy has to do with the different threads accessing the
same objects, so maybe you are on to something here.

This problem does seem restricted to a particular user using a particular
computer (a year-old Dell), but that computer does not have a dual
processor. In the case where you tracked it down to a dual processor, what
did you do to fix it?

Randy
 
J

Jason Hales

The .PDB can be deployed onto your users PC in the same folder as your
release build.

When you set the build to be a Release build you can also set Build |
Generate Debugging Informaton to true to get it to create a debug file
for your Release code (it's set to false by default). That way you'll
get line numbers in your StackTrace.

Note if you simply copy the PDB from your Debug build into your Release
build folder they won't match and you'll not get the line numbers

In terms of fixing the dual processor issue, I tidied up some poorly
written multi-threading code which I'd inherited. That fixed it :)
 
R

Randolph Neall

Jason, if you're still listening, I think you've put me on track to figuring
out what the problem might be, and it does probably involve threads
accessing a method in a form without invocation. That method in the
form--actually the application form--does not itself touch any of the form's
visual components, but still it shouldn't be being hit by outside threads. I
think that's my problem, and I'll be working to correct it today.

I still have a question for you. In several places in our application we
have cases where collections such as hash tables or queues are being
accessed raw by more than one thread without synchronization. I had thought
that so long as as collections like these were not being run through
for-next loop that multi-thread, unsynchronized, unprotected access was OK.
In other words, to add to or delete from collections such as these is OK
without thread synchronization. Is this wrong? And could I solve this
problem--if it is a problem--by placing a lock(this) {} around the methods
that access those collections?

Thanks,

Randy
 
J

Jason Hales

Hi Randy, yep still here

Yes enumerating through collections such as a Hashtable is NOT thread
safe (even if it was created via the Synchronized wrapper method)

Using a lock is what you need, but don't forget lock(this) will only
lock on the current object (this), which I assume is a class that
contains your Collection. You need to use lock(myCollection) assuming
mycollecton is the collection variable that you're accessing

If all else fails you could start with the greatest level of locking
and work your away down. You can use the
MethodImpl(MethodImplOptions.Synchronized) attribute at method level so
that the method can only be executed by one thread at a time. That's
the worse case situation though :)
From the UI point of view it might be worth looking at the
BackgroundWorker component in v2 of framework
 
R

Randolph Neall

Jason, hey what a resource you are! Of course enumerating through a
collection is not thread safe, but what about adding or deleting an item in
a collection? Do you have to worry about that, too? And do efforts at
synchronization, such as lock(this), or other methods come at much
performance expense? Do you have to lock(this) or worse ANY time an object
could be hit by more than one thread?

We've done quite well until VS2005 came out, and that seems to be uncovering
some sins.

Randy
 
J

Jason Hales

Glad to help out. From multi-threading point of view it's even worse
if you're adding/deleting from collections such as Hashtables. From
the VS2003 Help "To support one or more writers, all operations on the
Hashtable must be done through the wrapper returned by the Synchronized
method" and adding/deleting are writing operations.

Provided you serialise calls via the lock statement you should be safe.
So yes you must use lock - again to you need to determine if
lock(this) will give you enough scope or whether you need to use a
locking variable.

At one place I worked at last year I had a bizarre situation caused by
poor multithreading. I had a breakpoint set on a Property Get and I
was looking at a value, I looked away and looked back a few seconds
later to find that the value had changed. This is because someone had
used some code that checked for a null in the Property Get and if it
was null it would go and create an instance of the returning variable
and return that. Not only was this dangerous from a multi-threading
point of view but it was a questionable oo design choice - blurring
Property Gets/Sets.

In that situation this is the sort of construct that I used (also works
well with static members/value types):
private object columnList_LockObject = new object();
private ColumnList columnList = null;
public ColumnList Columns
{
get
{
if (columnList == null)
{
lock(columnList_LockObject)
{
if (columnList == null)
{
columnList = new ColumnList();
}
}
}
return columnList;
}
set { columnList = value; }
}

I don't think it's that painful too implement effective locking. Yes
it might be a bit slower, in terms of what the CLR has to do behind the
scenes to give you locking, and with queuing the other threads up but
it think it's a small price to pay for happy users :)

I'm going to be doing a lot more VS2005 starting in the next few weeks
- I guess I'll be finding more a few of these issues popping up too
 
R

Randolph Neall

Thanks, Jason. It looks like we'll need to make some more changes. You've
been a great help.
You'll have more of this sort of stuff cropping up in VS2005.

Thanks,

Randy
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top