Hopefully this is the right newsgroup. I figured you guys would be the best
experts on this.

I am learning C# and .NET and went a little crazy with the events. Now I am
not sure how to isolate this problem. Here is my architecture, I have:
1. an OpenGLPanel class derived from UserControl that handles the repainting
using OpenGL. A render event is published for subscribers to paint into the
window.
2. a Manipulator class that handles mouse and keyboard events to cause
rotations, scales, etc. using events.
3. a Camera class that rotates, zooms, etc. based on any subscriptions to a
Manipulator and posts view update events.

Okay, simple scenario, I have a form with two OpenGLPanels, visible. Each
has a camera and listens for the camera events. The camera listen for the
manipulator events. The manipulator listen's for the form's mouse and
keyboard events (a complete cycle!!!!!). The main form has a method to draw
an object and subscribes to the OpenGLPanel's render event.

Things work great in a serial world. I even could attach a manipulator to
both cameras, etc. Pretty cool!! I was just started to really like this new
environment. I decided to switch from just firing the event to doing an
asynchronous call (as a first step to remoting the camera). I would really
like a OneWay approach for the camera, but both of these destroy the OpenGL
context or something. Right now, I am only processing the camera updates to
the OpenGLPanel's asynchronously, but would suspect that all of the mouse
events are also handles asynchronously. The render events will always be
sequential, but I would also like to have the manipulator events happen
OneWay to the cameras.

The problem with the render made sense to me at first, if I set the active
rendering context and then the thread got bumped, etc. I added
[Synchronization] in front of the OpenGLPanel class. It and the Form1 class
are the only ones that make OpenGL calls. I get one of the Panels not
redrawing. The calls are all happening, but I think something in the state
got messed up. The other panel starts off blank and then when I force a
particular event (set of events) it shows up and works properly. Changing
the subscription order seems to reverse which panel works and which one does
not. Pretty much every method is atomic and nothing is left in a bad state
(if I programmed it correctly). I decided to add [Synchronization] before
all of my classes, but nothing helps. BTW, I never create any threads, just
those (two) from a default Windows form. I am running on a single CPU
machine.

Okay, now for the question(s):
1) Is this a correct way to protect a shared system resource?
2) Is there a better way?
3) Any guesses on what might be going on before I attempt to boil the code
down to a simpler test case (or assugn it as a midterm question :-) )?
4) I can see the High priority thread preempting the other thread, such that
mouse calls are continually triggered before any updates to the display can
finish. I would expect, that after I release the mouse and wait idle for
awhile the display would redraw.


Some other questions on multi-tasking:
4) My counter indicates I am still getting 70-90 frames-per-second, but
visually, it is more like 1-2 fps.
5) Are the events queued, or do I always just get the most recent event? If
they are queued, is there an easy way to only get the latest. I want to
display with the latest camera, not march thru all of the events.
6) How does a Windows form split up its tasks into threads? I know you want
the user interface thread to be at a high priority, is everything in the
form then issued at a low priority? This would include control updates and
displays, so ...

This is all educational code for my own amusement, so I happy to give the
entire project to anyone interested in looking into this further.

Roger Crawfis
Associate Professor
Computer Science and Engineering Dept.
The Ohio State University

Re: Asychronous events and rendering contexts by Ken

Ken
Mon Jan 24 20:35:55 CST 2005

See comments inline below...


"Roger Crawfis" <rcrawfis@columbus.rr.com> wrote in message
news:D9fJd.52010$re1.21206@fe2.columbus.rr.com...
>
> Hopefully this is the right newsgroup. I figured you guys would be the
> best
> experts on this.
>
> I am learning C# and .NET and went a little crazy with the events. Now I
> am
> not sure how to isolate this problem. Here is my architecture, I have:
> 1. an OpenGLPanel class derived from UserControl that handles the
> repainting
> using OpenGL. A render event is published for subscribers to paint into
> the
> window.
> 2. a Manipulator class that handles mouse and keyboard events to cause
> rotations, scales, etc. using events.
> 3. a Camera class that rotates, zooms, etc. based on any subscriptions to
> a
> Manipulator and posts view update events.
>
> Okay, simple scenario, I have a form with two OpenGLPanels, visible. Each
> has a camera and listens for the camera events. The camera listen for the
> manipulator events. The manipulator listen's for the form's mouse and
> keyboard events (a complete cycle!!!!!). The main form has a method to
> draw
> an object and subscribes to the OpenGLPanel's render event.
>
> Things work great in a serial world. I even could attach a manipulator to
> both cameras, etc. Pretty cool!! I was just started to really like this
> new
> environment. I decided to switch from just firing the event to doing an
> asynchronous call (as a first step to remoting the camera). I would really
> like a OneWay approach for the camera, but both of these destroy the
> OpenGL
> context or something. Right now, I am only processing the camera updates
> to
> the OpenGLPanel's asynchronously, but would suspect that all of the mouse
> events are also handles asynchronously. The render events will always be
> sequential, but I would also like to have the manipulator events happen
> OneWay to the cameras.
>
> The problem with the render made sense to me at first, if I set the active
> rendering context and then the thread got bumped, etc. I added
> [Synchronization] in front of the OpenGLPanel class. It and the Form1
> class
> are the only ones that make OpenGL calls. I get one of the Panels not
> redrawing. The calls are all happening, but I think something in the state
> got messed up. The other panel starts off blank and then when I force a
> particular event (set of events) it shows up and works properly. Changing
> the subscription order seems to reverse which panel works and which one
> does
> not. Pretty much every method is atomic and nothing is left in a bad state
> (if I programmed it correctly). I decided to add [Synchronization] before
> all of my classes, but nothing helps. BTW, I never create any threads,
> just
> those (two) from a default Windows form. I am running on a single CPU
> machine.
>
> Okay, now for the question(s):
> 1) Is this a correct way to protect a shared system resource?

I'm not sure why you're using the [Synchronization] attribute -- are you
using COM+ for some part of your implementation? Or do you mean that you're
using the [MethodImpl(MethodImplOption.Synchronized)]? I don't know anything
about OpenGL or what issues may be inherent in using it, however, there are
issues to be aware of when using async events with Windows Forms.

First is that event form has a UI thread on which all UI-based events must
be handled. This includes events that paint the user interface. So, if
you're painting on the UI from a thread you spawned by invoking an event
asynchronously, you will likely run into problems (and they're usually odd
behaviors as opposed to the UI crashing). Look into the Form.Invoke() method
for info on marshalling the calls back to the UI thread.

Also, you asked about whether mouse events happen asynchronously -- the
answer is No. Mouse events happen on the UI thread just like any other event
which comes to your window via the Windows message pump.

> 2) Is there a better way?

If you're just looking to make sure access to a data element is thread-safe,
use the lock() statement (in C#) to accomplish this. Locking creates
critical sections to prevent concurrent use of shared resources.

> 3) Any guesses on what might be going on before I attempt to boil the code
> down to a simpler test case (or assugn it as a midterm question :-) )?

Besides what I've mentioned before, no. I don't know enough about OpenGL to
know. If you can post a simply code sample, that could help in diagnosing
the problem.

> 4) I can see the High priority thread preempting the other thread, such
> that
> mouse calls are continually triggered before any updates to the display
> can
> finish. I would expect, that after I release the mouse and wait idle for
> awhile the display would redraw.
>
>
> Some other questions on multi-tasking:
> 4) My counter indicates I am still getting 70-90 frames-per-second, but
> visually, it is more like 1-2 fps.
> 5) Are the events queued, or do I always just get the most recent event?
> If
> they are queued, is there an easy way to only get the latest. I want to
> display with the latest camera, not march thru all of the events.

Events are queued, so if you want to optimize to prevent unnecessary
painting, you'll have to do this yourself.

> 6) How does a Windows form split up its tasks into threads? I know you
> want
> the user interface thread to be at a high priority, is everything in the
> form then issued at a low priority? This would include control updates and
> displays, so ...

As mentioned above, all of this is happening on the same thread. You, of
course, can spawn other threads to perform non-UI-related tasks and set the
priority on those thread accordingly.

Regards -
Ken



Re: Asychronous events and rendering contexts by Roger

Roger
Thu Jan 27 08:39:39 CST 2005

This is a multi-part message in MIME format.

------=_NextPart_000_007C_01C50454.A848BB70
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

Thanks Ken. The "this.Invoke()" was what I needed. I had to reorganize =
my code somewhat to accomplish this (yet another indirection), since the =
event publisher is not the Form for some of the events. OneWay now =
*seems to* work fine. The astericks are there because I am not totally =
confident it is correct. If I use BeginInvoke and then WaitOne(), it =
never returns. Below is my EventsHelper for this. It follows Juval =
Lowy's excellent book on "Programming .NET Components". He did not have =
any EndInvoke or Wait(). In fact, he states you can not call EndInvoke() =
when publishing asynchronously (p. 138). Most curious, but I think he =
means using the EventsHelper class. I really do not care about any =
return values, but thought I would give any threads a chance to process =
the events before moving on. A WaitOne(10, false) seems to work fine, =
but it will wait for 10 msec. Something is wrong in my logic below.

On the [Synchronization] attribute flag does not necessarily mean a COM =
object if I understand this book correctly. It provides automatic =
synchronization (locking) at the component level. This would imply to me =
that once a thread starts a method on a synchronious component, it will =
block all other threads trying to access it. It seems to work with the =
OneWay, as the individual methods are not thread safe without it.

Thank you very much for your time. I am trying to track down the .NET =
remoting issues now, so I may have another question (separate thread =
though).

EventsHelper.cs
----------[snip]
//

// Asynchronous event firing with exception catching

//

delegate void AsyncFire( Delegate client, object[] args );

public static void FireAsync( Delegate publishedEvent, =
params object[] args )

{

if( publishedEvent =3D=3D null )

return;

Delegate[] clientList =3D =
publishedEvent.GetInvocationList();

IAsyncResult[] asyncResult =3D new =
IAsyncResult[clientList.Length];

AsyncFire asyncClientCall;

int i =3D 0;

foreach( Delegate sink in clientList )

{

try

{

asyncClientCall =3D new AsyncFire( =
InvokeClient );

asyncResult[i] =3D =
asyncClientCall.BeginInvoke( sink, args, null, null );

i++;

}

catch{}

}

for( i=3D0; i < clientList.Length; i++ )

{

try

{

asyncResult[i].AsyncWaitHandle.WaitOne( =
10, false );

}

catch{}

}

}

private static void InvokeClient( Delegate client, object[] =
args )

{

client.DynamicInvoke( args );

}





"Ken Kolda" <nospam@spam.com> wrote in message =
news:%23AIWYaoAFHA.1084@tk2msftngp13.phx.gbl...
> See comments inline below...
>=20
>=20
> "Roger Crawfis" <rcrawfis@columbus.rr.com> wrote in message=20
> news:D9fJd.52010$re1.21206@fe2.columbus.rr.com...
>>
>> Hopefully this is the right newsgroup. I figured you guys would be =
the=20
>> best
>> experts on this.
>>
>> I am learning C# and .NET and went a little crazy with the events. =
Now I=20
>> am
>> not sure how to isolate this problem. Here is my architecture, I =
have:
>> 1. an OpenGLPanel class derived from UserControl that handles the=20
>> repainting
>> using OpenGL. A render event is published for subscribers to paint =
into=20
>> the
>> window.
>> 2. a Manipulator class that handles mouse and keyboard events to =
cause
>> rotations, scales, etc. using events.
>> 3. a Camera class that rotates, zooms, etc. based on any =
subscriptions to=20
>> a
>> Manipulator and posts view update events.
>>
>> Okay, simple scenario, I have a form with two OpenGLPanels, visible. =
Each
>> has a camera and listens for the camera events. The camera listen for =
the
>> manipulator events. The manipulator listen's for the form's mouse and
>> keyboard events (a complete cycle!!!!!). The main form has a method =
to=20
>> draw
>> an object and subscribes to the OpenGLPanel's render event.
>>
>> Things work great in a serial world. I even could attach a =
manipulator to
>> both cameras, etc. Pretty cool!! I was just started to really like =
this=20
>> new
>> environment. I decided to switch from just firing the event to doing =
an
>> asynchronous call (as a first step to remoting the camera). I would =
really
>> like a OneWay approach for the camera, but both of these destroy the=20
>> OpenGL
>> context or something. Right now, I am only processing the camera =
updates=20
>> to
>> the OpenGLPanel's asynchronously, but would suspect that all of the =
mouse
>> events are also handles asynchronously. The render events will always =
be
>> sequential, but I would also like to have the manipulator events =
happen
>> OneWay to the cameras.
>>
>> The problem with the render made sense to me at first, if I set the =
active
>> rendering context and then the thread got bumped, etc. I added
>> [Synchronization] in front of the OpenGLPanel class. It and the Form1 =

>> class
>> are the only ones that make OpenGL calls. I get one of the Panels not
>> redrawing. The calls are all happening, but I think something in the =
state
>> got messed up. The other panel starts off blank and then when I force =
a
>> particular event (set of events) it shows up and works properly. =
Changing
>> the subscription order seems to reverse which panel works and which =
one=20
>> does
>> not. Pretty much every method is atomic and nothing is left in a bad =
state
>> (if I programmed it correctly). I decided to add [Synchronization] =
before
>> all of my classes, but nothing helps. BTW, I never create any =
threads,=20
>> just
>> those (two) from a default Windows form. I am running on a single CPU
>> machine.
>>
>> Okay, now for the question(s):
>> 1) Is this a correct way to protect a shared system resource?
>=20
> I'm not sure why you're using the [Synchronization] attribute -- are =
you=20
> using COM+ for some part of your implementation? Or do you mean that =
you're=20
> using the [MethodImpl(MethodImplOption.Synchronized)]? I don't know =
anything=20
> about OpenGL or what issues may be inherent in using it, however, =
there are=20
> issues to be aware of when using async events with Windows Forms.
>=20
> First is that event form has a UI thread on which all UI-based events =
must=20
> be handled. This includes events that paint the user interface. So, if =

> you're painting on the UI from a thread you spawned by invoking an =
event=20
> asynchronously, you will likely run into problems (and they're usually =
odd=20
> behaviors as opposed to the UI crashing). Look into the Form.Invoke() =
method=20
> for info on marshalling the calls back to the UI thread.
>=20
> Also, you asked about whether mouse events happen asynchronously -- =
the=20
> answer is No. Mouse events happen on the UI thread just like any other =
event=20
> which comes to your window via the Windows message pump.
>=20
>> 2) Is there a better way?
>=20
> If you're just looking to make sure access to a data element is =
thread-safe,=20
> use the lock() statement (in C#) to accomplish this. Locking creates=20
> critical sections to prevent concurrent use of shared resources.
>=20
>> 3) Any guesses on what might be going on before I attempt to boil the =
code
>> down to a simpler test case (or assugn it as a midterm question :-) =
)?
>=20
> Besides what I've mentioned before, no. I don't know enough about =
OpenGL to=20
> know. If you can post a simply code sample, that could help in =
diagnosing=20
> the problem.
>=20
>> 4) I can see the High priority thread preempting the other thread, =
such=20
>> that
>> mouse calls are continually triggered before any updates to the =
display=20
>> can
>> finish. I would expect, that after I release the mouse and wait idle =
for
>> awhile the display would redraw.
>>
>>
>> Some other questions on multi-tasking:
>> 4) My counter indicates I am still getting 70-90 frames-per-second, =
but
>> visually, it is more like 1-2 fps.
>> 5) Are the events queued, or do I always just get the most recent =
event?=20
>> If
>> they are queued, is there an easy way to only get the latest. I want =
to
>> display with the latest camera, not march thru all of the events.
>=20
> Events are queued, so if you want to optimize to prevent unnecessary=20
> painting, you'll have to do this yourself.
>=20
>> 6) How does a Windows form split up its tasks into threads? I know =
you=20
>> want
>> the user interface thread to be at a high priority, is everything in =
the
>> form then issued at a low priority? This would include control =
updates and
>> displays, so ...
>=20
> As mentioned above, all of this is happening on the same thread. You, =
of=20
> course, can spawn other threads to perform non-UI-related tasks and =
set the=20
> priority on those thread accordingly.
>=20
> Regards -
> Ken
>=20
>
------=_NextPart_000_007C_01C50454.A848BB70
Content-Type: text/html;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META http-equiv=3DContent-Type content=3D"text/html; =
charset=3Diso-8859-1">
<META content=3D"MSHTML 6.00.2900.2523" name=3DGENERATOR>
<STYLE></STYLE>
</HEAD>
<BODY>
<DIV><FONT face=3DArial size=3D2>Thanks Ken. The "this.Invoke()" was =
what I needed.=20
I had to reorganize my code somewhat to accomplish this (yet another=20
indirection), since the event publisher is not the Form for some of the =
events.=20
OneWay now *seems to* work fine. The astericks are there because I am =
not=20
totally confident it is correct. If I use BeginInvoke and then =
WaitOne(), it=20
never returns. Below is my EventsHelper for this. It follows Juval =
Lowy's=20
excellent book on "Programming .NET Components". He did not have any =
EndInvoke=20
or Wait(). In fact, he states you can not call EndInvoke() when =
publishing=20
asynchronously (p. 138). Most curious, but I think he means using the=20
EventsHelper class. I really do not care about any return values, but =
thought I=20
would give any threads a chance to process the events before moving on. =
A=20
WaitOne(10, false) seems to work fine, but it will wait for 10 msec. =
Something=20
is wrong in my logic below.</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>On the [Synchronization] attribute flag =
does not=20
necessarily mean a COM object if I understand this book correctly. It =
provides=20
automatic synchronization (locking) at the component level. This would =
imply to=20
me that once a thread starts a method on a synchronious component, it =
will block=20
all other threads trying to access it. It seems to work with the OneWay, =
as the=20
individual methods are not thread safe without it.</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>Thank you very much for your time. I am =
trying to=20
track down the .NET remoting issues now, so I may have another question=20
(separate thread though).</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>EventsHelper.cs</FONT></DIV>
<DIV><FONT face=3DArial size=3D2>----------[snip]</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN><SPAN style=3D"COLOR: green">//<?xml:namespace prefix =3D o ns =
=3D=20
"urn:schemas-microsoft-com:office:office" =
/><o:p></o:p></SPAN></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN><SPAN style=3D"COLOR: green">// Asynchronous event firing with =
exception=20
catching<o:p></o:p></SPAN></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN><SPAN style=3D"COLOR: green">//<o:p></o:p></SPAN></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN><SPAN style=3D"COLOR: blue">delegate</SPAN> <SPAN=20
style=3D"COLOR: blue">void</SPAN> AsyncFire( Delegate client, <SPAN=20
style=3D"COLOR: blue">object</SPAN>[] args );<o:p></o:p></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN><SPAN style=3D"COLOR: blue">public</SPAN> <SPAN=20
style=3D"COLOR: blue">static</SPAN> <SPAN style=3D"COLOR: =
blue">void</SPAN>=20
FireAsync( Delegate publishedEvent, <SPAN style=3D"COLOR: =
blue">params</SPAN>=20
<SPAN style=3D"COLOR: blue">object</SPAN>[] args )<o:p></o:p></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN>{<o:p></o:p></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN><SPAN style=3D"COLOR: blue">if</SPAN>( publishedEvent =3D=3D =
<SPAN=20
style=3D"COLOR: blue">null</SPAN> )<o:p></o:p></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
4">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN><SPAN style=3D"COLOR: blue">return</SPAN>;<o:p></o:p></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN><SPAN style=3D"mso-tab-count: 1">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN>Delegate[] clientList =3D=20
publishedEvent.GetInvocationList();<o:p></o:p></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN>IAsyncResult[] asyncResult =3D <SPAN style=3D"COLOR: =
blue">new</SPAN>=20
IAsyncResult[clientList.Length];<o:p></o:p></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN>AsyncFire asyncClientCall;<o:p></o:p></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN><SPAN style=3D"COLOR: blue">int</SPAN> i =3D =
0;<o:p></o:p></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN><SPAN style=3D"COLOR: blue">foreach</SPAN>( Delegate sink <SPAN=20
style=3D"COLOR: blue">in</SPAN> clientList )<o:p></o:p></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN>{<o:p></o:p></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
4">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN><SPAN style=3D"COLOR: blue">try<o:p></o:p></SPAN></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
4">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN>{<o:p></o:p></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
5">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN>asyncClientCall =3D <SPAN style=3D"COLOR: blue">new</SPAN> =
AsyncFire(=20
InvokeClient );<o:p></o:p></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
5">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN>asyncResult[i] =3D asyncClientCall.BeginInvoke( sink, args, <SPAN =

style=3D"COLOR: blue">null</SPAN>, <SPAN style=3D"COLOR: =
blue">null</SPAN>=20
);<o:p></o:p></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
5">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN>i++;<o:p></o:p></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
4">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN>}<o:p></o:p></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
4">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN><SPAN style=3D"COLOR: blue">catch</SPAN>{}<o:p></o:p></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN>}<o:p></o:p></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN><SPAN style=3D"COLOR: blue">for</SPAN>( i=3D0; i &lt; =
clientList.Length; i++=20
)<o:p></o:p></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN>{<o:p></o:p></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
4">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN><SPAN style=3D"COLOR: blue">try<o:p></o:p></SPAN></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
4">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN>{<o:p></o:p></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
5">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp=
;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN>asyncResult[i].AsyncWaitHandle.WaitOne( 10, <SPAN=20
style=3D"COLOR: blue">false</SPAN> );<o:p></o:p></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
4">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN>}<o:p></o:p></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
4">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN><SPAN style=3D"COLOR: blue">catch</SPAN>{}<o:p></o:p></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN>}<o:p></o:p></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN>}<o:p></o:p></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN><SPAN style=3D"COLOR: blue">private</SPAN> <SPAN=20
style=3D"COLOR: blue">static</SPAN> <SPAN style=3D"COLOR: =
blue">void</SPAN>=20
InvokeClient( Delegate client, <SPAN style=3D"COLOR: =
blue">object</SPAN>[] args=20
)<o:p></o:p></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN>{<o:p></o:p></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
3">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs=
p;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN>client.DynamicInvoke( args );<o:p></o:p></SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><SPAN=20
style=3D"mso-tab-count: =
2">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;=20
</SPAN>}</SPAN></P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"></SPAN>&nbsp;</P>
<P class=3DMsoNormal=20
style=3D"MARGIN: 0in 0in 0pt; mso-layout-grid-align: none"><SPAN=20
style=3D"FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-bidi-language: =
AR-SA"><o:p></o:p></SPAN>&nbsp;</P></DIV>
<DIV><FONT face=3DArial size=3D2>"Ken Kolda" &lt;</FONT><A=20
href=3D"mailto:nospam@spam.com"><FONT face=3DArial=20
size=3D2>nospam@spam.com</FONT></A><FONT face=3DArial size=3D2>&gt; =
wrote in message=20
</FONT><A href=3D"news:%23AIWYaoAFHA.1084@tk2msftngp13.phx.gbl"><FONT =
face=3DArial=20
size=3D2>news:%23AIWYaoAFHA.1084@tk2msftngp13.phx.gbl</FONT></A><FONT =
face=3DArial=20
size=3D2>...</FONT></DIV><FONT face=3DArial size=3D2>&gt; See comments =
inline=20
below...<BR>&gt; <BR>&gt; <BR>&gt; "Roger Crawfis" &lt;</FONT><A=20
href=3D"mailto:rcrawfis@columbus.rr.com"><FONT face=3DArial=20
size=3D2>rcrawfis@columbus.rr.com</FONT></A><FONT face=3DArial =
size=3D2>&gt; wrote in=20
message <BR>&gt; </FONT><A=20
href=3D"news:D9fJd.52010$re1.21206@fe2.columbus.rr.com"><FONT =
face=3DArial=20
size=3D2>news:D9fJd.52010$re1.21206@fe2.columbus.rr.com</FONT></A><FONT =
face=3DArial=20
size=3D2>...<BR>&gt;&gt;<BR>&gt;&gt; Hopefully this is the right =
newsgroup. I=20
figured you guys would be the <BR>&gt;&gt; best<BR>&gt;&gt; experts on=20
this.<BR>&gt;&gt;<BR>&gt;&gt; I am learning C# and .NET and went a =
little crazy=20
with the events. Now I <BR>&gt;&gt; am<BR>&gt;&gt; not sure how to =
isolate this=20
problem. Here is my architecture, I have:<BR>&gt;&gt; 1. an OpenGLPanel =
class=20
derived from UserControl that handles the <BR>&gt;&gt; =
repainting<BR>&gt;&gt;=20
using OpenGL. A render event is published for subscribers to paint into=20
<BR>&gt;&gt; the<BR>&gt;&gt; window.<BR>&gt;&gt; 2. a Manipulator class =
that=20
handles mouse and keyboard events to cause<BR>&gt;&gt; rotations, =
scales, etc.=20
using events.<BR>&gt;&gt; 3. a Camera class that rotates, zooms, etc. =
based on=20
any subscriptions to <BR>&gt;&gt; a<BR>&gt;&gt; Manipulator and posts =
view=20
update events.<BR>&gt;&gt;<BR>&gt;&gt; Okay, simple scenario, I have a =
form with=20
two OpenGLPanels, visible. Each<BR>&gt;&gt; has a camera and listens for =
the=20
camera events. The camera listen for the<BR>&gt;&gt; manipulator events. =
The=20
manipulator listen's for the form's mouse and<BR>&gt;&gt; keyboard =
events (a=20
complete cycle!!!!!). The main form has a method to <BR>&gt;&gt;=20
draw<BR>&gt;&gt; an object and subscribes to the OpenGLPanel's render=20
event.<BR>&gt;&gt;<BR>&gt;&gt; Things work great in a serial world. I =
even could=20
attach a manipulator to<BR>&gt;&gt; both cameras, etc. Pretty cool!! I =
was just=20
started to really like this <BR>&gt;&gt; new<BR>&gt;&gt; =
environment.&nbsp; I=20
decided to switch from just firing the event to doing an<BR>&gt;&gt;=20
asynchronous call (as a first step to remoting the camera). I would=20
really<BR>&gt;&gt; like a OneWay approach for the camera, but both of =
these=20
destroy the <BR>&gt;&gt; OpenGL<BR>&gt;&gt; context or something. Right =
now, I=20
am only processing the camera updates <BR>&gt;&gt; to<BR>&gt;&gt; the=20
OpenGLPanel's asynchronously, but would suspect that all of the=20
mouse<BR>&gt;&gt; events are also handles asynchronously. The render =
events will=20
always be<BR>&gt;&gt; sequential, but I would also like to have the =
manipulator=20
events happen<BR>&gt;&gt; OneWay to the cameras.<BR>&gt;&gt;<BR>&gt;&gt; =
The=20
problem with the render made sense to me at first, if I set the=20
active<BR>&gt;&gt; rendering context and then the thread got bumped, =
etc. I=20
added<BR>&gt;&gt; [Synchronization] in front of the OpenGLPanel class. =
It and=20
the Form1 <BR>&gt;&gt; class<BR>&gt;&gt; are the only ones that make =
OpenGL=20
calls. I get one of the Panels not<BR>&gt;&gt; redrawing. The calls are =
all=20
happening, but I think something in the state<BR>&gt;&gt; got messed up. =
The=20
other panel starts off blank and then when I force a<BR>&gt;&gt; =
particular=20
event (set of events) it shows up and works properly. =
Changing<BR>&gt;&gt; the=20
subscription order seems to reverse which panel works and which one =
<BR>&gt;&gt;=20
does<BR>&gt;&gt; not. Pretty much every method is atomic and nothing is =
left in=20
a bad state<BR>&gt;&gt; (if I programmed it correctly). I decided to add =

[Synchronization] before<BR>&gt;&gt; all of my classes, but nothing =
helps. BTW,=20
I never create any threads, <BR>&gt;&gt; just<BR>&gt;&gt; those (two) =
from a=20
default Windows form. I am running on a single CPU<BR>&gt;&gt;=20
machine.<BR>&gt;&gt;<BR>&gt;&gt; Okay, now for the =
question(s):<BR>&gt;&gt; 1)=20
Is this a correct way to protect a shared system resource?<BR>&gt; =
<BR>&gt; I'm=20
not sure why you're using the [Synchronization] attribute -- are you =
<BR>&gt;=20
using COM+ for some part of your implementation? Or do you mean that =
you're=20
<BR>&gt; using the [MethodImpl(MethodImplOption.Synchronized)]? I don't =
know=20
anything <BR>&gt; about OpenGL or what issues may be inherent in using =
it,=20
however, there are <BR>&gt; issues to be aware of when using async =
events with=20
Windows Forms.<BR>&gt; <BR>&gt; First is that event form has a UI thread =
on=20
which all UI-based events must <BR>&gt; be handled. This includes events =
that=20
paint the user interface. So, if <BR>&gt; you're painting on the UI from =
a=20
thread you spawned by invoking an event <BR>&gt; asynchronously, you =
will likely=20
run into problems (and they're usually odd <BR>&gt; behaviors as opposed =
to the=20
UI crashing). Look into the Form.Invoke() method <BR>&gt; for info on=20
marshalling the calls back to the UI thread.<BR>&gt; <BR>&gt; Also, you =
asked=20
about whether mouse events happen asynchronously -- the <BR>&gt; answer =
is No.=20
Mouse events happen on the UI thread just like any other event <BR>&gt; =
which=20
comes to your window via the Windows message pump.<BR>&gt; <BR>&gt;&gt; =
2) Is=20
there a better way?<BR>&gt; <BR>&gt; If you're just looking to make sure =
access=20
to a data element is thread-safe, <BR>&gt; use the lock() statement (in =
C#) to=20
accomplish this. Locking creates <BR>&gt; critical sections to prevent=20
concurrent use of shared resources.<BR>&gt; <BR>&gt;&gt; 3) Any guesses =
on what=20
might be going on before I attempt to boil the code<BR>&gt;&gt; down to =
a=20
simpler test case (or assugn it as a midterm question :-) )?<BR>&gt; =
<BR>&gt;=20
Besides what I've mentioned before, no. I don't know enough about OpenGL =
to=20
<BR>&gt; know. If you can post a simply code sample, that could help in=20
diagnosing <BR>&gt; the problem.<BR>&gt; <BR>&gt;&gt; 4) I can see the =
High=20
priority thread preempting the other thread, such <BR>&gt;&gt; =
that<BR>&gt;&gt;=20
mouse calls are continually triggered before any updates to the display=20
<BR>&gt;&gt; can<BR>&gt;&gt; finish. I would expect, that after I =
release the=20
mouse and wait idle for<BR>&gt;&gt; awhile the display would=20
redraw.<BR>&gt;&gt;<BR>&gt;&gt;<BR>&gt;&gt; Some other questions on=20
multi-tasking:<BR>&gt;&gt; 4) My counter indicates I am still getting =
70-90=20
frames-per-second, but<BR>&gt;&gt; visually, it is more like 1-2=20
fps.<BR>&gt;&gt; 5) Are the events queued, or do I always just get the =
most=20
recent event? <BR>&gt;&gt; If<BR>&gt;&gt; they are queued, is there an =
easy way=20
to only get the latest. I want to<BR>&gt;&gt; display with the latest =
camera,=20
not march thru all of the events.<BR>&gt; <BR>&gt; Events are queued, so =
if you=20
want to optimize to prevent unnecessary <BR>&gt; painting, you'll have =
to do=20
this yourself.<BR>&gt; <BR>&gt;&gt; 6) How does a Windows form split up =
its=20
tasks into threads? I know you <BR>&gt;&gt; want<BR>&gt;&gt; the user =
interface=20
thread to be at a high priority, is everything in the<BR>&gt;&gt; form =
then=20
issued at a low priority? This would include control updates =
and<BR>&gt;&gt;=20
displays, so ...<BR>&gt; <BR>&gt; As mentioned above, all of this is =
happening=20
on the same thread. You, of <BR>&gt; course, can spawn other threads to =
perform=20
non-UI-related tasks and set the <BR>&gt; priority on those thread=20
accordingly.<BR>&gt; <BR>&gt; Regards -<BR>&gt; Ken<BR>&gt;=20
<BR>&gt;</FONT></BODY></HTML>

------=_NextPart_000_007C_01C50454.A848BB70--


Re: Asychronous events and rendering contexts by Ken

Ken
Thu Jan 27 10:33:20 CST 2005

This is a multi-part message in MIME format.

------=_NextPart_000_0034_01C5044A.DB7CB000
Content-Type: text/plain;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

The code you have looks good. The fact that WaitOne() doesn't return is =
odd though. The main reason I could see for this is that your =
FireAsync() method is being invoked on the UI thread (e.g. in response =
to a button click on a form) and one (or more) of the delegates being =
invoked is, in turn, calling Form.Invoke() to marshal the call to the UI =
thread. This would cause a deadlock condition so the WaitOne() won't =
return. Or there could be some other thread locking that's not shown in =
the code below (e.g. via marking a class as syncrhonized).

Ken

"Roger Crawfis" <rcrawfis@columbus.rr.com> wrote in message =
news:L27Kd.61439$re1.22831@fe2.columbus.rr.com...
Thanks Ken. The "this.Invoke()" was what I needed. I had to reorganize =
my code somewhat to accomplish this (yet another indirection), since the =
event publisher is not the Form for some of the events. OneWay now =
*seems to* work fine. The astericks are there because I am not totally =
confident it is correct. If I use BeginInvoke and then WaitOne(), it =
never returns. Below is my EventsHelper for this. It follows Juval =
Lowy's excellent book on "Programming .NET Components". He did not have =
any EndInvoke or Wait(). In fact, he states you can not call EndInvoke() =
when publishing asynchronously (p. 138). Most curious, but I think he =
means using the EventsHelper class. I really do not care about any =
return values, but thought I would give any threads a chance to process =
the events before moving on. A WaitOne(10, false) seems to work fine, =
but it will wait for 10 msec. Something is wrong in my logic below.

On the [Synchronization] attribute flag does not necessarily mean a =
COM object if I understand this book correctly. It provides automatic =
synchronization (locking) at the component level. This would imply to me =
that once a thread starts a method on a synchronious component, it will =
block all other threads trying to access it. It seems to work with the =
OneWay, as the individual methods are not thread safe without it.

Thank you very much for your time. I am trying to track down the .NET =
remoting issues now, so I may have another question (separate thread =
though).

EventsHelper.cs
----------[snip]
//

// Asynchronous event firing with exception catching

//

delegate void AsyncFire( Delegate client, object[] args );

public static void FireAsync( Delegate publishedEvent, =
params object[] args )

{

if( publishedEvent =3D=3D null )

return;

Delegate[] clientList =3D =
publishedEvent.GetInvocationList();

IAsyncResult[] asyncResult =3D new =
IAsyncResult[clientList.Length];

AsyncFire asyncClientCall;

int i =3D 0;

foreach( Delegate sink in clientList )

{

try

{

asyncClientCall =3D new AsyncFire( =
InvokeClient );

asyncResult[i] =3D =
asyncClientCall.BeginInvoke( sink, args, null, null );

i++;

}

catch{}

}

for( i=3D0; i < clientList.Length; i++ )

{

try

{

asyncResult[i].AsyncWaitHandle.WaitOne( =
10, false );

}

catch{}

}

}

private static void InvokeClient( Delegate client, =
object[] args )

{

client.DynamicInvoke( args );

}



=20

"Ken Kolda" <nospam@spam.com> wrote in message =
news:%23AIWYaoAFHA.1084@tk2msftngp13.phx.gbl...
> See comments inline below...
>=20
>=20
> "Roger Crawfis" <rcrawfis@columbus.rr.com> wrote in message=20
> news:D9fJd.52010$re1.21206@fe2.columbus.rr.com...
>>
>> Hopefully this is the right newsgroup. I figured you guys would be =
the=20
>> best
>> experts on this.
>>
>> I am learning C# and .NET and went a little crazy with the events. =
Now I=20
>> am
>> not sure how to isolate this problem. Here is my architecture, I =
have:
>> 1. an OpenGLPanel class derived from UserControl that handles the=20
>> repainting
>> using OpenGL. A render event is published for subscribers to paint =
into=20
>> the
>> window.
>> 2. a Manipulator class that handles mouse and keyboard events to =
cause
>> rotations, scales, etc. using events.
>> 3. a Camera class that rotates, zooms, etc. based on any =
subscriptions to=20
>> a
>> Manipulator and posts view update events.
>>
>> Okay, simple scenario, I have a form with two OpenGLPanels, =
visible. Each
>> has a camera and listens for the camera events. The camera listen =
for the
>> manipulator events. The manipulator listen's for the form's mouse =
and
>> keyboard events (a complete cycle!!!!!). The main form has a method =
to=20
>> draw
>> an object and subscribes to the OpenGLPanel's render event.
>>
>> Things work great in a serial world. I even could attach a =
manipulator to
>> both cameras, etc. Pretty cool!! I was just started to really like =
this=20
>> new
>> environment. I decided to switch from just firing the event to =
doing an
>> asynchronous call (as a first step to remoting the camera). I would =
really
>> like a OneWay approach for the camera, but both of these destroy =
the=20
>> OpenGL
>> context or something. Right now, I am only processing the camera =
updates=20
>> to
>> the OpenGLPanel's asynchronously, but would suspect that all of the =
mouse
>> events are also handles asynchronously. The render events will =
always be
>> sequential, but I would also like to have the manipulator events =
happen
>> OneWay to the cameras.
>>
>> The problem with the render made sense to me at first, if I set the =
active
>> rendering context and then the thread got bumped, etc. I added
>> [Synchronization] in front of the OpenGLPanel class. It and the =
Form1=20
>> class
>> are the only ones that make OpenGL calls. I get one of the Panels =
not
>> redrawing. The calls are all happening, but I think something in =
the state
>> got messed up. The other panel starts off blank and then when I =
force a
>> particular event (set of events) it shows up and works properly. =
Changing
>> the subscription order seems to reverse which panel works and which =
one=20
>> does
>> not. Pretty much every method is atomic and nothing is left in a =
bad state
>> (if I programmed it correctly). I decided to add [Synchronization] =
before
>> all of my classes, but nothing helps. BTW, I never create any =
threads,=20
>> just
>> those (two) from a default Windows form. I am running on a single =
CPU
>> machine.
>>
>> Okay, now for the question(s):
>> 1) Is this a correct way to protect a shared system resource?
>=20
> I'm not sure why you're using the [Synchronization] attribute -- are =
you=20
> using COM+ for some part of your implementation? Or do you mean that =
you're=20
> using the [MethodImpl(MethodImplOption.Synchronized)]? I don't know =
anything=20
> about OpenGL or what issues may be inherent in using it, however, =
there are=20
> issues to be aware of when using async events with Windows Forms.
>=20
> First is that event form has a UI thread on which all UI-based =
events must=20
> be handled. This includes events that paint the user interface. So, =
if=20
> you're painting on the UI from a thread you spawned by invoking an =
event=20
> asynchronously, you will likely run into problems (and they're =
usually odd=20
> behaviors as opposed to the UI crashing). Look into the =
Form.Invoke() method=20
> for info on marshalling the calls back to the UI thread.
>=20
> Also, you asked about whether mouse events happen asynchronously -- =
the=20
> answer is No. Mouse events happen on the UI thread just like any =
other event=20
> which comes to your window via the Windows message pump.
>=20
>> 2) Is there a better way?
>=20
> If you're just looking to make sure access to a data element is =
thread-safe,=20
> use the lock() statement (in C#) to accomplish this. Locking creates =

> critical sections to prevent concurrent use of shared resources.
>=20
>> 3) Any guesses on what might be going on before I attempt to boil =
the code
>> down to a simpler test case (or assugn it as a midterm question :-) =
)?
>=20
> Besides what I've mentioned before, no. I don't know enough about =
OpenGL to=20
> know. If you can post a simply code sample, that could help in =
diagnosing=20
> the problem.
>=20
>> 4) I can see the High priority thread preempting the other thread, =
such=20
>> that
>> mouse calls are continually triggered before any updates to the =
display=20
>> can
>> finish. I would expect, that after I release the mouse and wait =
idle for
>> awhile the display would redraw.
>>
>>
>> Some other questions on multi-tasking:
>> 4) My counter indicates I am still getting 70-90 frames-per-second, =
but
>> visually, it is more like 1-2 fps.
>> 5) Are the events queued, or do I always just get the most recent =
event?=20
>> If
>> they are queued, is there an easy way to only get the latest. I =
want to
>> display with the latest camera, not march thru all of the events.
>=20
> Events are queued, so if you want to optimize to prevent unnecessary =

> painting, you'll have to do this yourself.
>=20
>> 6) How does a Windows form split up its tasks into threads? I know =
you=20
>> want
>> the user interface thread to be at a high priority, is everything =
in the
>> form then issued at a low priority? This would include control =
updates and
>> displays, so ...
>=20
> As mentioned above, all of this is happening on the same thread. =
You, of=20
> course, can spawn other threads to perform non-UI-related tasks and =
set the=20
> priority on those thread accordingly.
>=20
> Regards -
> Ken
>=20
>
------=_NextPart_000_0034_01C5044A.DB7CB000
Content-Type: text/html;
charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML xmlns:o =3D "urn:schemas-microsoft-com:office:office"><HEAD>
<META http-equiv=3DContent-Type content=3D"text/html; =
charset=3Diso-8859-1">
<META content=3D"MSHTML 6.00.2800.1479" name=3DGENERATOR>
<STYLE></STYLE>
</HEAD>
<BODY bgColor=3D#ffffff>
<DIV><FONT face=3DArial size=3D2>The code you have looks good. The fact =
that=20
WaitOne() doesn't return is odd though. The main reason I could see for =
this is=20
that your FireAsync() method is being invoked on the UI thread (e.g. in =
response=20
to a button click on a form) and one (or more) of the delegates being =
invoked=20
is, in turn, calling Form.Invoke() to marshal the call to the UI thread. =
This=20
would cause a deadlock condition so the WaitOne() won't return. Or there =
could=20
be some other thread locking that's not shown in the code below (e.g. =
via=20
marking a class as syncrhonized).</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<DIV><FONT face=3DArial size=3D2>Ken</FONT></DIV>
<DIV><FONT face=3DArial size=3D2></FONT>&nbsp;</DIV>
<BLOCKQUOTE=20
style=3D"PADDING-RIGHT: 0px; PADDING-LEFT: 5px; MARGIN-LEFT: 5px; =
BORDER-LEFT: #000000 2px solid; MARGIN-RIGHT: 0px">
<DIV>"Roger Crawfis" &lt;<A=20
=
href=3D"mailto:rcrawfis@columbus.rr.com">rcrawfis@columbus.rr.com</A>&gt;=
wrote=20
in message <A=20
=
href=3D"news:L27Kd.61439$re1.22831@fe2.columbus.rr.com">news:L27Kd.61439$=
re1.22831@fe2.columbus.rr.com</A>...</DIV>
<DIV><FONT face=3DArial size=3D2>Thanks Ken. The "this.Invoke()" was =
what I=20
needed. I had to reorganize my code somewhat to accomplish this (yet =
another=20
indirection), since the event publisher is not the Form for some of =
the=20
events. OneWay now *seems to* work fine. The astericks are there =
because I am=20
not totally confident it is