Multithreaded GUI issues

P

pedrito

I posted an issue a couple of days ago that nobody has answered anything on
yet (re: error in System.Net.OSSOCK.closesocket()) and I'm starting to
wonder if maybe my problem lies elsewhere.

As I mentioned in that post, the app is multithreaded. It downloads from a
number of threads simultaneously. There are 4 or 5 events that can come off
of these separate threads.

In each of these cases, where the events get passed on to GUI components,
they're Invoked into the GUI thread.

But then it occurred to me, is there a specific "line in the sand"? What GUI
methods are callable from separate threads and which ones aren't?

For example, some of these threads might download images and in those cases,
I'm creating Image objects (on non-gui threads) to get information about the
images (dimensions mainly), though they're never drawn. But does this
constitute the wrong side of the line?

Clearly some GUI-side methods can, and should be called from separate
threads. Control.InvokeRequired and Control.Invoke(), obviously.

Is there a list somewhere of what's safe and what's not safe to call from a
non-gui thread? I mean, sometimes it's hard to know for sure if something in
the framework is eventually going to do GUI side work even though it might
not be apparent from the call.

Thanks.
 
P

Peter Duniho

pedrito said:
I posted an issue a couple of days ago that nobody has answered anything on
yet (re: error in System.Net.OSSOCK.closesocket()) and I'm starting to
wonder if maybe my problem lies elsewhere.

I saw that. I didn't see a post constructed clearly enough to make it
worth trying to reply. I can't speak for anyone else, but that's why I
didn't bother to comment on it.

I will point out that there wasn't any indication in your post that you
were actually trying to close a socket at the time the exception
occurred, so you might want to check to see why something is trying to
close a socket when you don't expect to.
As I mentioned in that post, the app is multithreaded. It downloads from a
number of threads simultaneously. There are 4 or 5 events that can come off
of these separate threads.

In each of these cases, where the events get passed on to GUI components,
they're Invoked into the GUI thread.

But then it occurred to me, is there a specific "line in the sand"? What GUI
methods are callable from separate threads and which ones aren't?

None can. You must use Invoke() or BeginInvoke() on any code that will
eventually access a Control-derived instance.

Okay, that's not strictly true. But you should follow that rule,
because AFAIK Microsoft hasn't published any guidance regarding what's
safe to do and what's not. And also AFAIK practically everything that
you might do with an existing .NET Control-derived class needs to be
invoked on that Control-derived instance's owning thread (most of the
methods and properties in those classes translate to some underlying
window message, and that's where the thread-specific requirement comes
from).

Obviously if you subclass a Control class, then your own implementation
is known to you and you can easily tell what's safe to execute on
another thread or not. But for consistency you may want to follow the
same rule anyway. The other benefit of doing so is that using Invoke()
or BeginInvoke() ensures synchronization of code executing that deals
with the Control-derived instance.
For example, some of these threads might download images and in those cases,
I'm creating Image objects (on non-gui threads) to get information about the
images (dimensions mainly), though they're never drawn. But does this
constitute the wrong side of the line?

It depends on what you do with the Image objects and any resulting data
(like the dimensions).
Clearly some GUI-side methods can, and should be called from separate
threads. Control.InvokeRequired and Control.Invoke(), obviously.

Anything that is literally affecting the GUI needs to use Invoke().
Is there a list somewhere of what's safe and what's not safe to call from a
non-gui thread? I mean, sometimes it's hard to know for sure if something in
the framework is eventually going to do GUI side work even though it might
not be apparent from the call.

I'm not not really clear on what you mean here. It seems to me that if
you assume that anything that uses an instance of a Control-derived
class needs to be done on the GUI thread, that is the safest, most
reliable practice. Likewise, if your code does not actually access the
Control-derived instance, there should be no problem.

Of course, you need to keep track of things you may have done in your
code that would indirectly cause access to a Control-derived class. But
that would all be in your own implementation. I'm not aware of things
that you might do with non-GUI objects that could still affect or
otherwise interact with GUI objects.

Whether any of this has anything to do with your original problem, I
can't say.

Pete
 
P

pedrito

Peter Duniho said:
I saw that. I didn't see a post constructed clearly enough to make it
worth trying to reply. I can't speak for anyone else, but that's why I
didn't bother to comment on it.

In what way did you find it no "constructed clearly enough" I provided the
code. I showed precisely where the exception was occurring. The code is
happening in a try/catch handler, but the exception is taking place in a
callback thread that I have no control over. .NET is creating the callback
internally.

I showed the call stack of that callback. I thought I "constructed" my
question as clearly as I could. What other information could I provide to
clear it up? I'm not trying to be defensive. I'm just trying to understand
what's unclear so that I can clarify. I would like to find the solution.

I will point out that there wasn't any indication in your post that you
were actually trying to close a socket at the time the exception occurred,
so you might want to check to see why something is trying to close a
socket when you don't expect to.

Well, no, I wasn't trying to close the socket. The socket is, I suspect,
getting closed by the web server, possibly unexpectedly. It happens. My app
doesn't expect a well-behaved server which is why there's a big try/catch
around the whole thing. But since the exception is happening on a .NET
framework callback that I have no control over, I can't catch that
exception. So how do I create an app that deals with poorly behaved servers
if that's the case.
None can. You must use Invoke() or BeginInvoke() on any code that will
eventually access a Control-derived instance.

Okay, that's not strictly true. But you should follow that rule, because
AFAIK Microsoft hasn't published any guidance regarding what's safe to do
and what's not. And also AFAIK practically everything that you might do
with an existing .NET Control-derived class needs to be invoked on that
Control-derived instance's owning thread (most of the methods and
properties in those classes translate to some underlying window message,
and that's where the thread-specific requirement comes from).

My point is your second part. Your first part, "none can" is not a precise
answer because it's not "strictly true". My question was, and I think I was
pretty clear about it, what is the dillineation? Is it things that force
paints off the GUI thread? Is it accessing certain data within GUI controls?
Is there any guieline? You say, "practically everything," but again, not
specific.

I'm not trying to bitch here, really. I'm just pointing out that my question
was specifically what. It's okay to say you don't know. But that was my
question.
Obviously if you subclass a Control class, then your own implementation is
known to you and you can easily tell what's safe to execute on another
thread or not. But for consistency you may want to follow the same rule
anyway. The other benefit of doing so is that using Invoke() or
BeginInvoke() ensures synchronization of code executing that deals with
the Control-derived instance.


It depends on what you do with the Image objects and any resulting data
(like the dimensions).

Getting the dimensions and doing a comparison to see if the image is within
a certain size range. Probably not going to be a problem. But how do I know
that creating an Image object is thread safe? Is it? I've never read that it
isn't, but that's really what I was asking.
Anything that is literally affecting the GUI needs to use Invoke().


I'm not not really clear on what you mean here. It seems to me that if
you assume that anything that uses an instance of a Control-derived class
needs to be done on the GUI thread, that is the safest, most reliable
practice. Likewise, if your code does not actually access the
Control-derived instance, there should be no problem.

Of course, you need to keep track of things you may have done in your code
that would indirectly cause access to a Control-derived class. But that
would all be in your own implementation. I'm not aware of things that you
might do with non-GUI objects that could still affect or otherwise
interact with GUI objects.

Whether any of this has anything to do with your original problem, I can't
say.

At this point, I'm starting to think it's not an issue with a non-GUI thread
causing updates since after going through each thread individually in nProf
has shown that all the calls from the separate threads end up in what I
assume are thread safe methods. If they aren't, Invoke() and InvokeRequired
are broken.

Thanks for answering, and really, please do tell me what you think was
unclear about my original post and I'll try to clarify.
 
S

Smithers

<snip>

RE:
<< I'm not aware of things that you might do with non-GUI objects that could
still affect or otherwise interact with GUI objects>>

I ran into something last week that might be more or less relevant to this
conversation:

The FileSystemWatcher class events are raised, automatically, on separate
threads spawned by the FileSystemWatcher class, itself. So, when updating UI
components from these events, it is possible to get this exception:
"Cross-thread operation not valid: Control 'xyz' accessed from a thread
other than the thread it was created on." Two ways I have found to solve
this: (1) Make use of this.Invoke() to call the code that updates the UI
control, or (2) Set the FileSystemWatcher.SynchronizingObject property to
reference the form class. I have not run into the .SynchronizingObject
property elsewhere, but perhaps other framework classes have it or something
similar.

-S
 
P

pedrito

Smithers said:
<snip>

RE:
<< I'm not aware of things that you might do with non-GUI objects that
could still affect or otherwise interact with GUI objects>>

I ran into something last week that might be more or less relevant to this
conversation:

The FileSystemWatcher class events are raised, automatically, on separate
threads spawned by the FileSystemWatcher class, itself. So, when updating
UI components from these events, it is possible to get this exception:
"Cross-thread operation not valid: Control 'xyz' accessed from a thread
other than the thread it was created on." Two ways I have found to solve
this: (1) Make use of this.Invoke() to call the code that updates the UI
control, or (2) Set the FileSystemWatcher.SynchronizingObject property to
reference the form class. I have not run into the .SynchronizingObject
property elsewhere, but perhaps other framework classes have it or
something similar.

-S

Yeah, there was one other non-GUI thread event that I had going which was a
System.Timer.Timer.Elapsed event. That's happening in my main application
(non-gui code) which then calls into the GUI. Before doing so, it checks to
make sure that the application main form is non-null and that it has a
message loop (via a boolean I set to true in the OnLoad() and false in
OnClosing()) and then it Invokes into the GUI thread before calling stuff in
the GUI.

So that's all pretty clean.

Really, I think I've isolated all the thread stuff pretty well. I don't see
(and at this point, nProf appears to be backing it up) anywhere that non-GUI
threads can be crossing the line.
 
P

Peter Duniho

pedrito said:
In what way did you find it no "constructed clearly enough" I provided the
code. I showed precisely where the exception was occurring. The code is
happening in a try/catch handler, but the exception is taking place in a
callback thread that I have no control over. .NET is creating the callback
internally.

It's hard to even know where to start. All I can say at this moment,
without going back and deconstructing your previous posts, is that I did
not feel that the code you posted and the exception you posted appeared
to be at all related.

Your comment above reinforces that. Showing us the code for one thread,
and then telling us about an exception that happens in a completely
different thread tells us very little about either thread. If the
exception didn't occur in thread using the code you posted, then there's
really no assurance that the exception has anything to do with the code
that was posted.

If I have more time later, and you are really interested, I will see if
I can go through the post more carefully and provide better feedback.

The bottom line here is that all of us are busy. I am, you are,
everyone else is. While I think it's important for a community to help
those in need, this has to be balanced with the effort required to
address that need.

In the case of your post, I found that the effort required simply to try
to understand what you were trying to tell us exceeded my threshold of
tolerance, especially given that in such situations I often find myself
without an answer anyway, in spite of spending a lot of time trying to
decipher the post.

I don't know that everyone else had the same impression. But the lack
of any reply suggests that might be the case. There's a lot of other
smart, experienced folks reading this newsgroup and well-constructed
questions almost always get some kind of reply, even if it's just some
sort of educated guess.
Well, no, I wasn't trying to close the socket.

That's my point. The stack trace appears to be code that _is_ trying to
close the socket. Since you didn't do that, that's a problem. Find the
code that's trying to close the socket, and you likely will find your
culprit.
The socket is, I suspect,
getting closed by the web server, possibly unexpectedly. It happens.

Not really. That is, the _connection_ may be closed. But the web
server doesn't have the power to close your socket. Only you do. If
the connection closes, normally that causes an exception (actually, a
socket error WSAECONNRESET that gets thrown as a SocketException). But
the socket itself remains unclosed until you call Close() on it.
My app
doesn't expect a well-behaved server which is why there's a big try/catch
around the whole thing. But since the exception is happening on a .NET
framework callback that I have no control over, I can't catch that
exception. So how do I create an app that deals with poorly behaved servers
if that's the case.

My recollection is that there is not enough information in your previous
post to understand in what context the exception is occurring or why
your own code isn't involved.

Other than that, I don't have anything useful to offer at the moment.
My point is your second part. Your first part, "none can" is not a precise
answer because it's not "strictly true". My question was, and I think I was
pretty clear about it, what is the dillineation? Is it things that force
paints off the GUI thread? Is it accessing certain data within GUI controls?
Is there any guieline? You say, "practically everything," but again, not
specific.

My point is that you MUST assume that it's "none can", because Microsoft
offers no information about what can.

The only way in which it is reasonably "not strictly true" is when you
are calling your own methods in a derived class. For example, if you
inherit Form in your class, and then implement a method that doesn't
actually do anything with the inherited Form class. That method may
well be safe to call from another thread (assuming no other
synchronization issues, of course).

But other than situations like that, do not ever access an instance of a
class derived from Control on any thread other than the thread that owns
that instance.
I'm not trying to bitch here, really. I'm just pointing out that my question
was specifically what. It's okay to say you don't know. But that was my
question.

I don't know.

There. Now, just to reinforce what I'm saying above: you must remember
that practically all of the .NET Control-derived classes are basically
just wrappers to pre-existing unmanaged Windows control classes. Those
classes have no function-based API; all interaction with them is done
via window messages.

For example, consider TextBox. Whether you are retrieving the text from
the control, setting the text, changing the selection, hiding the
control, showing the control, enabling the control, disabling the
control, etc. that all goes through the window message system. There is
essentially nothing useful you can do with the control that doesn't in
some way go through the window message system. That imposes the
requirement that you only access the control from the thread that owns it.

Now, in unmanaged code, this is typically handled for you when you call
SendMessage(). That unmanaged function will automatically block the
calling thread and execute the necessary window procedure on the actual
owning thread. I'm not sure why .NET doesn't have a similar behavior;
this would be like just implicitly always calling Invoke() when necessary.

But the fact is, it doesn't. If you are interacting with one of these
Controls in any way, you pretty much always have to use Invoke() or
BeginInvoke() when doing so from a thread other than the one that owns
the Control.

No exceptions. None that are officially acknowledged, anyway.
Getting the dimensions and doing a comparison to see if the image is within
a certain size range. Probably not going to be a problem. But how do I know
that creating an Image object is thread safe? Is it? I've never read that it
isn't, but that's really what I was asking.

An Image object isn't a GUI object. You can do anything you want with
it, without worrying about cross-thread issues. It's if and when the
results of your operations on the Image object get passed to some object
that is a GUI object that you get into trouble.

If you don't do that, no worries. If you do, worries.

Now, none of that means that you can simply ignore cross-thread issues.
The issue with Control-derived classes is a special, particular one.
But you always need to worry about synchronization if you have data that
is being accessed by multiple threads. It's just that those worries are
different from the one that requires you to call Control.Invoke().

Ironically, even though it may not be required (see above regarding
calling your own methods that don't actually use the base class
members), often using Control.Invoke() or Control.BeginInvoke() is the
most straightforward way to ensure this synchronization. So it's easy
to get the issues confused. But do take care: they aren't the same issues.
[...]
Thanks for answering, and really, please do tell me what you think was
unclear about my original post and I'll try to clarify.

I don't have enough time (especially after writing this post :) ) to
review your previous post. But if I find time, I'll try to.

Pete
 
G

Guest

Hello,
Check the property : Form.CheckForIllegalCrossThreadCalls

From msdn :
Gets or sets a value indicating whether to catch calls on the wrong thread
that access a control's Handle property.
true if calls on the wrong thread are caught; otherwise, false.

Using it you can trap a method call safty state to a gui thread.
 
P

pedrito

Yaron Karni said:
Hello,
Check the property : Form.CheckForIllegalCrossThreadCalls

From msdn :
Gets or sets a value indicating whether to catch calls on the wrong thread
that access a control's Handle property.
true if calls on the wrong thread are caught; otherwise, false.

Using it you can trap a method call safty state to a gui thread.

Sadly, I'm working in .NET 1.1 land... I may port over to 2.0 just to see if
that can help, though. Thanks for the information.
 
P

pedrito

I finally tracked down the problem and the symptoms weren't much help. It
was basically a result of trial and error. I was using the FreeImage image
library and when I removed the code that used it (basically some code to
load images and check for integrity), the error went away and everything
worked. Why it was throwing an exception deep in the winsock code, I don't
know...

Thanks to everyone for their help.
 

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