tags:

views:

148

answers:

2

Is there a (or, do you have your own) preferred way to do background processing in slices on the UI thread in Windows Forms? Like OnIdle() in MFC?

In native Windows programming you could roll your own message loop to do this, but Application.Run() doesn't give us access to the message loop.

The Application.Idle event gives us no way to trigger it repeatedly.

I guess you could call native PostMessage() with P/Invoke (since there's no managed version) to post yourself a private "WM_IDLE" message, and override WndProc() to catch it. I don't know how this would get along with Application.Run().

So far I've used a short Timer for this, but I'm afraid I may be losing cycles sleeping, especially since the actual Timer resolution is coarser than the nominal 1 ms minimum.

+1  A: 

The best option I've seen is to use a modified version of the Managed DirectX Render Loop designed by Tom Miller. By adding a call to Thread.Sleep() inside the render loop, you can pull your CPU usage down dramatically.

This does require a P/Invoke call to track that the application is still idle, but as long as it's idle, you can make a "timer" that fires continuously during the idle phases, and use that to do your processing.

That being said, on modern systems, you almost always have extra cores. I would suggest just doing the processing on a true background thread.

Reed Copsey
1. AFAIK many of my users don't have "modern systems" by that definition.2. UI is rapidly using new data generated by background process, hence all the usual multithreading problems.3. 99% of the work is in the background process, so separate cores for UI and background won't buy much more total throughput.
Conrad Albrecht
@Conrad: Which why I actually did give you an option that stays entirely on the UI thread... However, even "low end" systems from the last 3-5 years typically have 2 cores. Putting all of your processing onto a background thread lets you keep your UI active, even in a single-core low end system, and is probably easier than trying to do scheduled processing during idle times. That being said, the approach above works very well...
Reed Copsey
@Conrad: I just realized - I had the wrong link! The one I put in above should make much more sense... It uses Application.Idle with AppStileIdle in a loop - allowing you to do what you wanted. (Sorry about that - I pasted the wrong one previuosly).
Reed Copsey
Re bg thread easier: I'm trying to think through the details of syncing the 2 threads (UI displaying the data generated so far and bg thread generating more data) and it seems more complicated to me.
Conrad Albrecht
Re wrong link: makes sense now! (The old link was to a known *poor* solution.) A little P/Invoke for PeekMessage() and it looks good. Marked "accepted answer".
Conrad Albrecht
A: 

I thought of my own possible answer, inspired by Reed's talk of multithreading. I may have a way to retrigger Application.Idle:

Create a hidden form, let's call it formRetrigger.

In Application.Idle, launch my Retrigger() method on a thread pool thread.

Retrigger() calls formRetrigger.InvokeOnClick() (or any of the other "Control.Invoke" methods). I expect this to launch another message through Application's queue, causing Idle to get triggered again.

Conrad Albrecht