Thread Logic Question

J

Jordan

All,

I have a UI form calling a class object that contains a timer that
routinely draws intensive information to the screen (~30 fps). The
drawing is invoked on the main UI thread. I need the user to be able
to interact with the UI while the drawing is happening (dynamically
change drawing properties). Since the drawing is happening on the main
UI thread, the UI form doesn't receive the user control events
consistently (if at all).

Does anyone have some suggestions on how to model this scenario so that
I can receive events on the UI form but continue to draw? How would I
tackle this in C#? Thanks.
 
D

Dave Sexton

Hi Jordan,

For one thing you could try using the clip rectangle to update only a single portion of the display at a time. When you Invalidate
the display only invalidate specific regions that have become "dirty".

I would also try to come up with the most effecient drawing code that you can.

Another option might be to just use Managed DirectX.
 
N

Nicholas Paldino [.NET/C# MVP]

Jordan,

My guess is that you make one call to a method in your main form which
then does all the drawing logic.

What I would recommend is breaking up that method, if possible, into
smaller parts, and then calling each of those, so that you can have some
responsiveness to your app.

Hope this helps.
 
J

Jordan

Dave,

Thanks for your response. I'm using managed OpenGL to handle the
drawing so the entire screen is being updated. I'm actually writing an
extension to an OpenGL app so my control over the rendering context is
limited.
 
J

Jordan

Nicholas,

This is "kind of" true. The form contains a class that contains a
timer. The timer fires approximately 30 fps in which a call is made to
refresh the display. I then perform the drawing in the contained class
in response to the event. The form is quiescent until the timer is
fired.

Does breaking up C# code into smaller functions allow events to be
delegated between method calls (even if it is on the same thread)?
Jordan,

My guess is that you make one call to a method in your main form which
then does all the drawing logic.

What I would recommend is breaking up that method, if possible, into
smaller parts, and then calling each of those, so that you can have some
responsiveness to your app.

Hope this helps.

--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)

Jordan said:
All,

I have a UI form calling a class object that contains a timer that
routinely draws intensive information to the screen (~30 fps). The
drawing is invoked on the main UI thread. I need the user to be able
to interact with the UI while the drawing is happening (dynamically
change drawing properties). Since the drawing is happening on the main
UI thread, the UI form doesn't receive the user control events
consistently (if at all).

Does anyone have some suggestions on how to model this scenario so that
I can receive events on the UI form but continue to draw? How would I
tackle this in C#? Thanks.
 
P

Peter Duniho

Jordan said:
Nicholas,

This is "kind of" true. The form contains a class that contains a
timer. The timer fires approximately 30 fps in which a call is made to
refresh the display. I then perform the drawing in the contained class
in response to the event. The form is quiescent until the timer is
fired.

Does breaking up C# code into smaller functions allow events to be
delegated between method calls (even if it is on the same thread)?

I think he's suggesting that by doing that, you can explicitly allow for
more moments in time in which your UI can handle events.

It sounds as though it may be that your rendering does not actually itself
interact with your form. Is that true? That is, it doesn't need access to
anything in the form itself?

If so, then it seems to me that a better solution would be to put the
rendering in its own thread, on a loop throttled using a wait object (eg
event handle) with a timeout. You would calculate the timeout based on the
current time and the next actual time you need to do some work. Then the
thread would block unless that timeout expired, or some other thread
signaled your wait object. Then the main thread with the UI can respond to
user input, modifying whatever state is relevant as a result and signaling
the wait object on the other thread. When the rendering thread wakes up, it
can then process that user input as necessary and render if necessary.

If the rendering thread need not actually do anything immediately in
response to user input, you could even just forego signalling it from the
main thread, and instead just synchronize access to whatever shared data
moves user input information from the main thread to the rendering thread
(which you need to do regardless). You would still use a wait object (so
that the thread can easily be woken up for the purpose of exiting) and a
timeout (to ensure that rendering only happens every 33ms)...the main thread
just wouldn't bother signaling the rendering thread just for user input.

It's hard to say exactly what the right approach is without knowing
precisely what you're doing, but the above is a common enough technique for
decoupling user input from rendering performance.

Pete
 
J

Jordan

Peter,

I'm not entirely sure it is safe to do drawing in a thread when using
OpenGL. OpenGL is a state machine and not thread safe. You are
correct in that my form does not draw to itself but another device
context. However, the architecture of our system forces all drawing to
be invoked on the UI thread (trying to modify this behavior results in
evil voodoo).

Additionally, C# does not provide access to data members that were
created in a different thread. I'm thinking the best thing in this
case is going to be to make my drawing as skinny as possible. I've
re-worked a lot of the code, and the issue seems to have gone away.

Thanks all for your insightfull comments! This gives me a much better
understanding of how UI and threading interface.
 
N

Nicholas Paldino [.NET/C# MVP]

Jordan,

See inline:
I'm not entirely sure it is safe to do drawing in a thread when using
OpenGL. OpenGL is a state machine and not thread safe. You are
correct in that my form does not draw to itself but another device
context. However, the architecture of our system forces all drawing to
be invoked on the UI thread (trying to modify this behavior results in
evil voodoo).

Well, you are supposed to do all drawing operations in the UI thread.
Additionally, C# does not provide access to data members that were
created in a different thread.

This isn't true. You can access anything you want in separate threads,
you just have to make sure that the method that is called as the thread
routine has access to them. Protecting those fields from accesses from
different threads is another story though.
I'm thinking the best thing in this
case is going to be to make my drawing as skinny as possible. I've
re-worked a lot of the code, and the issue seems to have gone away.

That was the general idea. I recommended breaking it up into smaller
pieces so that the message pump could eventually pump messages corresponding
to your input, and give it a chance to respond.
 
J

Jordan

Cool! Sounds good. Thanks.
Jordan,

See inline:
I'm not entirely sure it is safe to do drawing in a thread when using
OpenGL. OpenGL is a state machine and not thread safe. You are
correct in that my form does not draw to itself but another device
context. However, the architecture of our system forces all drawing to
be invoked on the UI thread (trying to modify this behavior results in
evil voodoo).

Well, you are supposed to do all drawing operations in the UI thread.
Additionally, C# does not provide access to data members that were
created in a different thread.

This isn't true. You can access anything you want in separate threads,
you just have to make sure that the method that is called as the thread
routine has access to them. Protecting those fields from accesses from
different threads is another story though.
I'm thinking the best thing in this
case is going to be to make my drawing as skinny as possible. I've
re-worked a lot of the code, and the issue seems to have gone away.

That was the general idea. I recommended breaking it up into smaller
pieces so that the message pump could eventually pump messages corresponding
to your input, and give it a chance to respond.


--
- Nicholas Paldino [.NET/C# MVP]
- (e-mail address removed)
Thanks all for your insightfull comments! This gives me a much better
understanding of how UI and threading interface.
 
P

Peter Duniho

Jordan said:
I'm not entirely sure it is safe to do drawing in a thread when using
OpenGL. OpenGL is a state machine and not thread safe.

I've seen comments like this before here, and I think it bears clarification
that there's no such thing as either doing something in a thread or not
doing something in a thread.

Everything your program does, it does in a thread. You may only have a
single thread, but there is still a thread. A corollary to this is that you
can do anything you want, in any thread, as long as what you're doing is
completely isolated to that thread.

In the case of interaction with a form, since the form is owned by a thread,
and all Window messages for that form have to be processed on that thread,
it's not possible to isolate drawing that the form does in a way that allows
it to happen on another thread. But that doesn't mean that graphics
rendering in general can't happen on another thread. If there's an API that
allows for rendering without interaction with the form (or some other
Windows object that's owned by the form's owning thread), that can happen on
a different thread.
You are
correct in that my form does not draw to itself but another device
context. However, the architecture of our system forces all drawing to
be invoked on the UI thread (trying to modify this behavior results in
evil voodoo).

Okay...absent posted code, and in light of the fact that I don't know how
OpenGL support works, I'll take your word that you cannot separate OpenGL
rendering from the stuff that goes on in the form's owning thread.
Additionally, C# does not provide access to data members that were
created in a different thread.

As Nicholas says, that's incorrect.
I'm thinking the best thing in this
case is going to be to make my drawing as skinny as possible. I've
re-worked a lot of the code, and the issue seems to have gone away.

Glad to hear you've got a solution that works for you.

Pete
 
D

Dave Sexton

Hi Jordan,

Unless you're using the System.Windows.Forms.Timer or explicitly marshaling the timer calls to the UI thread, your drawing code is
probably executing on a thread other than the UI thread.

I only mention this because you never said which type of Timer you're using and you seemed to imply that breaking up the drawing
function into multiple methods has helped, which leads me to believe that you're executing that code on a different thread to begin
with. This is contrary to your statement, "the architecture of our system forces all drawing to be invoked on the UI thread".

HTH
 
J

Jordan

Dave,

No, it is drawing in the main UI thread. Here is what happens:

1) Class uses server timer (System.Timers.Timer)
2) Timer elapsed - call to RedrawViewers
3) Internally, RedrawViewers invokes to the main UI thread
4) Main UI thread handles OnAfterDraw event and paints to screen

What I did was make the painting more efficient and lower the FPS timer
rate (if I jump to 60 fps, it gets messy again).
 

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