HighTechTalks DotNet Forums  

Unexpected reentrancy on Wait,etc...

Dotnet Framework (CLR) microsoft.public.dotnet.framework.clr


Discuss Unexpected reentrancy on Wait,etc... in the Dotnet Framework (CLR) forum.



Reply
 
Thread Tools Search this Thread Display Modes
  #1  
Old   
jaket
 
Posts: n/a

Default Unexpected reentrancy on Wait,etc... - 11-02-2007 , 07:39 PM






Hello,

I have run into a serious reentrancy problem. It appears from a stack
trace that lock, WaitOne and Thread.Join do some servicing of the
message queue. Here is the setup:

The GUI thread uses a combination of Application.Idle and a timer to
simulate the old MFC OnIdle. The Idle handling will periodically pick
up some work that requires executing some non-reentrant code. This
code uses several locks to synchronize with other threads.

Another background worker thread is calling thru the Application's
API. The API must use Control.Invoke using the MainForm to marshal
the calls to the GUI thread. It also calls the non-reentrant code.

While GUI thread is waiting on a lock (I presume that it is already
held by a 3rd thread), the Control.Invoke can occassionaly slip thru
and cause reentrancy. Anyone familiar with the perils of DoEvents
will understand why this is a major problem.

Any suggestions?

Sincerely, Jake


Reply With Quote
  #2  
Old   
Frank Hileman
 
Posts: n/a

Default Re: Unexpected reentrancy on Wait,etc... - 11-05-2007 , 06:31 PM






Hi Jake,

Usually some code using locks can be reworked such that each thread works
with private copies of data only, returning data using a centralized queue,
with only the centralized queue being thread safe (using locks or other
techniques).

If you don't mind your reentrant function failing, set a boolean field to
true on entry of the function, and set it to false in a finally statement at
the end of the function (the body being in a try). Then add a check to the
top of the function to bail out if you are already executing the function.
That is the standard non-reentrancy guard.

Regards,
Frank Hileman

check out VG.net: http://www.vgdotnet.com
Animated vector graphics system
Integrated Visual Studio graphics editor

"jaket" <jtummond (AT) gmail (DOT) com> wrote

Quote:
Hello,

I have run into a serious reentrancy problem. It appears from a stack
trace that lock, WaitOne and Thread.Join do some servicing of the
message queue. Here is the setup:

The GUI thread uses a combination of Application.Idle and a timer to
simulate the old MFC OnIdle. The Idle handling will periodically pick
up some work that requires executing some non-reentrant code. This
code uses several locks to synchronize with other threads.

Another background worker thread is calling thru the Application's
API. The API must use Control.Invoke using the MainForm to marshal
the calls to the GUI thread. It also calls the non-reentrant code.

While GUI thread is waiting on a lock (I presume that it is already
held by a 3rd thread), the Control.Invoke can occassionaly slip thru
and cause reentrancy. Anyone familiar with the perils of DoEvents
will understand why this is a major problem.

Any suggestions?

Sincerely, Jake




Reply With Quote
  #3  
Old   
jaket
 
Posts: n/a

Default Re: Unexpected reentrancy on Wait,etc... - 11-06-2007 , 05:14 PM



I suppose the non-reentrant code could be moved into a new thread with
a queue. This doesn't solve the general problem that the GUI can
reenter anytime it locks and it is very difficult to guarantee the
rest of the GUI code is reentrant. Re your second point. The code is
currently guarded and throws an exception indicating the caller
violated the transaction discipline. Failure is not an option because
the receiver could be a customer calling thru the API.

Thanks for your suggestions,

Jake

On Nov 5, 3:31 pm, "Frank Hileman"
<frank... (AT) no (DOT) spamming.prodigesoftware.com> wrote:
Quote:
Hi Jake,

Usually some code using locks can be reworked such that each thread works
with private copies of data only, returning data using a centralized queue,
with only the centralized queue being thread safe (using locks or other
techniques).

If you don't mind your reentrant function failing, set a boolean field to
true on entry of the function, and set it to false in a finally statement at
the end of the function (the body being in a try). Then add a check to the
top of the function to bail out if you are already executing the function.
That is the standard non-reentrancy guard.

Regards,
Frank Hileman

check out VG.net:http://www.vgdotnet.com
Animated vector graphics system
Integrated Visual Studio graphics editor

"jaket" <jtumm... (AT) gmail (DOT) com> wrote in message

news:1194046798.871695.228490 (AT) k35g2000prh (DOT) googlegroups.com...



Hello,

I have run into a serious reentrancy problem. It appears from a stack
trace that lock, WaitOne and Thread.Join do some servicing of the
message queue. Here is the setup:

The GUI thread uses a combination of Application.Idle and a timer to
simulate the old MFC OnIdle. The Idle handling will periodically pick
up some work that requires executing some non-reentrant code. This
code uses several locks to synchronize with other threads.

Another background worker thread is calling thru the Application's
API. The API must use Control.Invoke using the MainForm to marshal
the calls to the GUI thread. It also calls the non-reentrant code.

While GUI thread is waiting on a lock (I presume that it is already
held by a 3rd thread), the Control.Invoke can occassionaly slip thru
and cause reentrancy. Anyone familiar with the perils of DoEvents
will understand why this is a major problem.

Any suggestions?

Sincerely, Jake- Hide quoted text -

- Show quoted text -



Reply With Quote
  #4  
Old   
Peter Ritchie [C# MVP]
 
Posts: n/a

Default Re: Unexpected reentrancy on Wait,etc... - 11-07-2007 , 10:09 AM



The GUI thread is an STA thread. A STA thread has an obligation to
responsively process its message pump. Standard wait methods in .NET
recognize this and process the threads message pump while waiting (wait
methods that don't, like WaitAll, will cause an exception when executed on an
STA thread).

Given that this is a GUI thread, you shouldn't block the thread with
lock/Wait/Join as this will block the responsiveness of the UI.

Idle is raised when there's no more windows message in the current GUI
thread's message queue. It's an indication that the GUI thread may not be
doing anything. If you want to take the opportunity to do something, then I
would spawn a background thread to do the work. If you need to communicate
something back to the GUI then I would recommend using a BackgroundWorker
object.

--
Browse http://connect.microsoft.com/VisualStudio/feedback/ and vote.
http://www.peterRitchie.com/blog/
Microsoft MVP, Visual Developer - Visual C#


"jaket" wrote:

Quote:
I suppose the non-reentrant code could be moved into a new thread with
a queue. This doesn't solve the general problem that the GUI can
reenter anytime it locks and it is very difficult to guarantee the
rest of the GUI code is reentrant. Re your second point. The code is
currently guarded and throws an exception indicating the caller
violated the transaction discipline. Failure is not an option because
the receiver could be a customer calling thru the API.

Thanks for your suggestions,

Jake

On Nov 5, 3:31 pm, "Frank Hileman"
frank... (AT) no (DOT) spamming.prodigesoftware.com> wrote:
Hi Jake,

Usually some code using locks can be reworked such that each thread works
with private copies of data only, returning data using a centralized queue,
with only the centralized queue being thread safe (using locks or other
techniques).

If you don't mind your reentrant function failing, set a boolean field to
true on entry of the function, and set it to false in a finally statement at
the end of the function (the body being in a try). Then add a check to the
top of the function to bail out if you are already executing the function.
That is the standard non-reentrancy guard.

Regards,
Frank Hileman

check out VG.net:http://www.vgdotnet.com
Animated vector graphics system
Integrated Visual Studio graphics editor

"jaket" <jtumm... (AT) gmail (DOT) com> wrote in message

news:1194046798.871695.228490 (AT) k35g2000prh (DOT) googlegroups.com...



Hello,

I have run into a serious reentrancy problem. It appears from a stack
trace that lock, WaitOne and Thread.Join do some servicing of the
message queue. Here is the setup:

The GUI thread uses a combination of Application.Idle and a timer to
simulate the old MFC OnIdle. The Idle handling will periodically pick
up some work that requires executing some non-reentrant code. This
code uses several locks to synchronize with other threads.

Another background worker thread is calling thru the Application's
API. The API must use Control.Invoke using the MainForm to marshal
the calls to the GUI thread. It also calls the non-reentrant code.

While GUI thread is waiting on a lock (I presume that it is already
held by a 3rd thread), the Control.Invoke can occassionaly slip thru
and cause reentrancy. Anyone familiar with the perils of DoEvents
will understand why this is a major problem.

Any suggestions?

Sincerely, Jake- Hide quoted text -

- Show quoted text -




Reply With Quote
  #5  
Old   
jaket
 
Posts: n/a

Default Re: Unexpected reentrancy on Wait,etc... - 11-07-2007 , 02:53 PM



Peter,

OnIdle is used to purposely slow updates to the GUI. Computations are
happening on a separate thread. Invoking onto the GUI thread from the
computation thread would not be feasable because the computations
sometimes happen too fast for the user's eye. Instead, the results
are written to a mailbox and the GUI checks the mailbox during Idle
time and updates. The locks are not held by either thread for long.
I don't understand how locks can be avoided in a multi-threaded
application, especially where data must be shared between the threads?

Thanks for your input, Jake

On Nov 7, 7:09 am, Peter Ritchie [C# MVP] <PRS... (AT) newsgroups (DOT) nospam>
wrote:
Quote:
The GUI thread is an STA thread. A STA thread has an obligation to
responsively process its message pump. Standard wait methods in .NET
recognize this and process the threads message pump while waiting (wait
methods that don't, like WaitAll, will cause an exception when executed on an
STA thread).

Given that this is a GUI thread, you shouldn't block the thread with
lock/Wait/Join as this will block the responsiveness of the UI.

Idle is raised when there's no more windows message in the current GUI
thread's message queue. It's an indication that the GUI thread may not be
doing anything. If you want to take the opportunity to do something, then I
would spawn a background thread to do the work. If you need to communicate
something back to the GUI then I would recommend using a BackgroundWorker
object.

--
Browsehttp://connect.microsoft.com/VisualStudio/feedback/and vote.http://www.peterRitchie.com/blog/
Microsoft MVP, Visual Developer - Visual C#



"jaket" wrote:
I suppose the non-reentrant code could be moved into a new thread with
a queue. This doesn't solve the general problem that the GUI can
reenter anytime it locks and it is very difficult to guarantee the
rest of the GUI code is reentrant. Re your second point. The code is
currently guarded and throws an exception indicating the caller
violated the transaction discipline. Failure is not an option because
the receiver could be a customer calling thru the API.

Thanks for your suggestions,

Jake

On Nov 5, 3:31 pm, "Frank Hileman"
frank... (AT) no (DOT) spamming.prodigesoftware.com> wrote:
Hi Jake,

Usually some code using locks can be reworked such that each thread works
with private copies of data only, returning data using a centralized queue,
with only the centralized queue being thread safe (using locks or other
techniques).

If you don't mind your reentrant function failing, set a boolean field to
true on entry of the function, and set it to false in a finally statement at
the end of the function (the body being in a try). Then add a check to the
top of the function to bail out if you are already executing the function.
That is the standard non-reentrancy guard.

Regards,
Frank Hileman

check out VG.net:http://www.vgdotnet.com
Animated vector graphics system
Integrated Visual Studio graphics editor

"jaket" <jtumm... (AT) gmail (DOT) com> wrote in message

news:1194046798.871695.228490 (AT) k35g2000prh (DOT) googlegroups.com...

Hello,

I have run into a serious reentrancy problem. It appears from a stack
trace that lock, WaitOne and Thread.Join do some servicing of the
message queue. Here is the setup:

The GUI thread uses a combination of Application.Idle and a timer to
simulate the old MFC OnIdle. The Idle handling will periodically pick
up some work that requires executing some non-reentrant code. This
code uses several locks to synchronize with other threads.

Another background worker thread is calling thru the Application's
API. The API must use Control.Invoke using the MainForm to marshal
the calls to the GUI thread. It also calls the non-reentrant code.

While GUI thread is waiting on a lock (I presume that it is already
held by a 3rd thread), the Control.Invoke can occassionaly slip thru
and cause reentrancy. Anyone familiar with the perils of DoEvents
will understand why this is a major problem.

Any suggestions?

Sincerely, Jake- Hide quoted text -

- Show quoted text -- Hide quoted text -

- Show quoted text -



Reply With Quote
  #6  
Old   
jaket
 
Posts: n/a

Default Re: Unexpected reentrancy on Wait,etc... - 11-15-2007 , 02:06 PM



I found an old blog entry from Chris Brumme discussing the exact
problem in grueling detail. If anyone is interested:

http://blogs.msdn.com/cbrumme/archiv.../02/66219.aspx



On Nov 2, 3:39 pm, jaket <jtumm... (AT) gmail (DOT) com> wrote:
Quote:
Hello,

I have run into a serious reentrancy problem. It appears from a stack
trace that lock, WaitOne and Thread.Join do some servicing of the
message queue. Here is the setup:

The GUI thread uses a combination of Application.Idle and a timer to
simulate the old MFC OnIdle. The Idle handling will periodically pick
up some work that requires executing some non-reentrant code. This
code uses several locks to synchronize with other threads.

Another background worker thread is calling thru the Application's
API. The API must use Control.Invoke using the MainForm to marshal
the calls to the GUI thread. It also calls the non-reentrant code.

While GUI thread is waiting on a lock (I presume that it is already
held by a 3rd thread), the Control.Invoke can occassionaly slip thru
and cause reentrancy. Anyone familiar with the perils of DoEvents
will understand why this is a major problem.

Any suggestions?

Sincerely, Jake


Reply With Quote
Reply




Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off



Powered by vBulletin Version 3.5.4
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.