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> </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> </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> </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"> =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"> =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"> =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"> =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"> =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"> =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"> &nbs=
p; =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"> &nbs=
p; =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"> =20
</SPAN><SPAN style=3D"mso-tab-count: 1"> =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"> &nbs=
p; =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"> &nbs=
p; =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"> &nbs=
p; =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"> &nbs=
p; =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"> &nbs=
p; =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"> &nbs=
p; =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"> &nbs=
p; =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"> &nbs=
p;  =
; =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"> &nbs=
p;  =
; =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"> &nbs=
p;  =
; =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"> &nbs=
p; =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"> &nbs=
p; =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"> &nbs=
p; =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"> &nbs=
p; =20
</SPAN><SPAN style=3D"COLOR: blue">for</SPAN>( i=3D0; i < =
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"> &nbs=
p; =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"> &nbs=
p; =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"> &nbs=
p; =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"> &nbs=
p;  =
; =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"> &nbs=
p; =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"> &nbs=
p; =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"> &nbs=
p; =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"> =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"> =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"> =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"> &nbs=
p; =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"> =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> </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> </P></DIV>
<DIV><FONT face=3DArial size=3D2>"Ken Kolda" <</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>> =
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>> See comments =
inline=20
below...<BR>> <BR>> <BR>> "Roger Crawfis" <</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>> wrote in=20
message <BR>> </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>>><BR>>> Hopefully this is the right =
newsgroup. I=20
figured you guys would be the <BR>>> best<BR>>> experts on=20
this.<BR>>><BR>>> I am learning C# and .NET and went a =
little crazy=20
with the events. Now I <BR>>> am<BR>>> not sure how to =
isolate this=20
problem. Here is my architecture, I have:<BR>>> 1. an OpenGLPanel =
class=20
derived from UserControl that handles the <BR>>> =
repainting<BR>>>=20
using OpenGL. A render event is published for subscribers to paint into=20
<BR>>> the<BR>>> window.<BR>>> 2. a Manipulator class =
that=20
handles mouse and keyboard events to cause<BR>>> rotations, =
scales, etc.=20
using events.<BR>>> 3. a Camera class that rotates, zooms, etc. =
based on=20
any subscriptions to <BR>>> a<BR>>> Manipulator and posts =
view=20
update events.<BR>>><BR>>> Okay, simple scenario, I have a =
form with=20
two OpenGLPanels, visible. Each<BR>>> has a camera and listens for =
the=20
camera events. The camera listen for the<BR>>> manipulator events. =
The=20
manipulator listen's for the form's mouse and<BR>>> keyboard =
events (a=20
complete cycle!!!!!). The main form has a method to <BR>>>=20
draw<BR>>> an object and subscribes to the OpenGLPanel's render=20
event.<BR>>><BR>>> Things work great in a serial world. I =
even could=20
attach a manipulator to<BR>>> both cameras, etc. Pretty cool!! I =
was just=20
started to really like this <BR>>> new<BR>>> =
environment. I=20
decided to switch from just firing the event to doing an<BR>>>=20
asynchronous call (as a first step to remoting the camera). I would=20
really<BR>>> like a OneWay approach for the camera, but both of =
these=20
destroy the <BR>>> OpenGL<BR>>> context or something. Right =
now, I=20
am only processing the camera updates <BR>>> to<BR>>> the=20
OpenGLPanel's asynchronously, but would suspect that all of the=20
mouse<BR>>> events are also handles asynchronously. The render =
events will=20
always be<BR>>> sequential, but I would also like to have the =
manipulator=20
events happen<BR>>> OneWay to the cameras.<BR>>><BR>>> =
The=20
problem with the render made sense to me at first, if I set the=20
active<BR>>> rendering context and then the thread got bumped, =
etc. I=20
added<BR>>> [Synchronization] in front of the OpenGLPanel class. =
It and=20
the Form1 <BR>>> class<BR>>> are the only ones that make =
OpenGL=20
calls. I get one of the Panels not<BR>>> redrawing. The calls are =
all=20
happening, but I think something in the state<BR>>> got messed up. =
The=20
other panel starts off blank and then when I force a<BR>>> =
particular=20
event (set of events) it shows up and works properly. =
Changing<BR>>> the=20
subscription order seems to reverse which panel works and which one =
<BR>>>=20
does<BR>>> not. Pretty much every method is atomic and nothing is =
left in=20
a bad state<BR>>> (if I programmed it correctly). I decided to add =
[Synchronization] before<BR>>> all of my classes, but nothing =
helps. BTW,=20
I never create any threads, <BR>>> just<BR>>> those (two) =
from a=20
default Windows form. I am running on a single CPU<BR>>>=20
machine.<BR>>><BR>>> Okay, now for the =
question(s):<BR>>> 1)=20
Is this a correct way to protect a shared system resource?<BR>> =
<BR>> I'm=20
not sure why you're using the [Synchronization] attribute -- are you =
<BR>>=20
using COM+ for some part of your implementation? Or do you mean that =
you're=20
<BR>> using the [MethodImpl(MethodImplOption.Synchronized)]? I don't =
know=20
anything <BR>> about OpenGL or what issues may be inherent in using =
it,=20
however, there are <BR>> issues to be aware of when using async =
events with=20
Windows Forms.<BR>> <BR>> First is that event form has a UI thread =
on=20
which all UI-based events must <BR>> be handled. This includes events =
that=20
paint the user interface. So, if <BR>> you're painting on the UI from =
a=20
thread you spawned by invoking an event <BR>> asynchronously, you =
will likely=20
run into problems (and they're usually odd <BR>> behaviors as opposed =
to the=20
UI crashing). Look into the Form.Invoke() method <BR>> for info on=20
marshalling the calls back to the UI thread.<BR>> <BR>> Also, you =
asked=20
about whether mouse events happen asynchronously -- the <BR>> answer =
is No.=20
Mouse events happen on the UI thread just like any other event <BR>> =
which=20
comes to your window via the Windows message pump.<BR>> <BR>>> =
2) Is=20
there a better way?<BR>> <BR>> If you're just looking to make sure =
access=20
to a data element is thread-safe, <BR>> use the lock() statement (in =
C#) to=20
accomplish this. Locking creates <BR>> critical sections to prevent=20
concurrent use of shared resources.<BR>> <BR>>> 3) Any guesses =
on what=20
might be going on before I attempt to boil the code<BR>>> down to =
a=20
simpler test case (or assugn it as a midterm question :-) )?<BR>> =
<BR>>=20
Besides what I've mentioned before, no. I don't know enough about OpenGL =
to=20
<BR>> know. If you can post a simply code sample, that could help in=20
diagnosing <BR>> the problem.<BR>> <BR>>> 4) I can see the =
High=20
priority thread preempting the other thread, such <BR>>> =
that<BR>>>=20
mouse calls are continually triggered before any updates to the display=20
<BR>>> can<BR>>> finish. I would expect, that after I =
release the=20
mouse and wait idle for<BR>>> awhile the display would=20
redraw.<BR>>><BR>>><BR>>> Some other questions on=20
multi-tasking:<BR>>> 4) My counter indicates I am still getting =
70-90=20
frames-per-second, but<BR>>> visually, it is more like 1-2=20
fps.<BR>>> 5) Are the events queued, or do I always just get the =
most=20
recent event? <BR>>> If<BR>>> they are queued, is there an =
easy way=20
to only get the latest. I want to<BR>>> display with the latest =
camera,=20
not march thru all of the events.<BR>> <BR>> Events are queued, so =
if you=20
want to optimize to prevent unnecessary <BR>> painting, you'll have =
to do=20
this yourself.<BR>> <BR>>> 6) How does a Windows form split up =
its=20
tasks into threads? I know you <BR>>> want<BR>>> the user =
interface=20
thread to be at a high priority, is everything in the<BR>>> form =
then=20
issued at a low priority? This would include control updates =
and<BR>>>=20
displays, so ...<BR>> <BR>> As mentioned above, all of this is =
happening=20
on the same thread. You, of <BR>> course, can spawn other threads to =
perform=20
non-UI-related tasks and set the <BR>> priority on those thread=20
accordingly.<BR>> <BR>> Regards -<BR>> Ken<BR>>=20
<BR>></FONT></BODY></HTML>
------=_NextPart_000_007C_01C50454.A848BB70--