views:

257

answers:

2

I have a Windows Form with a ListView in Report Mode. For each item in the view, I need to perform a long running operation, the result of which is a number.

The way I would do this in native win32 is to create a worker thread for each item (naively; of course I won't create an unbounded number of threads) and then MsgWaitForMultipleObjects() on the array of thread handles. As each calculation finishes, the threads signal and the main UI thread wakes up and updates. In the mean time, we pump messages so the UI thread remains responsive.

Can anyone provide an example of how this might work in C#? I've looked at the Monitor object, and it doesn't seem to be what I want—or does it pump messages while blocking?

Thanks.

Edit: It seems that WaitHandler.WaitAny() might actually pump messages. See cbrumme's treatise on message pumping in the CLR.

+1  A: 

Hello.

The long-running active object, I think, is the best choose in your case. The main thread calls the proxy (of active object). Proxy converts the call method to the message and this message is going to a queue. Proxy returns to the caller the future object (it is a reference to the future result). The dispatcher dequeues messages one by one and realy executes your task in other thread (working thread). When working thread completes a task, it updates the result of the future object or calls callback method (for example, to update your UI).Dispather can have many working threads to execute more the one task at the same time.

You can see this article (with sample) about long-running active object pattern.

igor
Please provide some information, and not just links to information.
John Saunders
Hmm, that really seems like a lot of code to solve such a simple problem. I mean, I could always just pinvoke my own COM object if I wanted to. If the C# framework isn't mature enough to let me do this easily, I can just go back to writing win32 code. Though I have to believe their is an easy way to do this.
jeffamaphone
Yes, you are right. This is an example from MSDN:connection1.Open(); SqlCommand command1 = new SqlCommand(commandText1, connection1); IAsyncResult result1 = command1.BeginExecuteNonQuery(); WaitHandle waitHandle1 = result1.AsyncWaitHandle; connection2.Open(); ... WaitHandle[] waitHandles = { waitHandle1, waitHandle2, waitHandle3 }; bool result = WaitHandle.WaitAll(waitHandles, 60000, false);
igor
+2  A: 

Have your main thread create a manager thread. You could use the BackgroundWorker for this. This manager thread kicks off a worker thread for each item in the ListView. This will allow your UI to keep responding to user input without hanging while the background threads are processing.

Now, the problem is how to wait for each worker thread to finish. Unfortunately, I have been unable to find a way to get a thread handle for System.Threading.Thread objects. I'm not saying there isn't a way to do it; I just haven't found one. Another complicating aspect to this is that the System.Threading.Thread class is sealed, so we can't derive from it to provide some kind of 'handle'.

This is where I use ManualResetEvent.

Let's say each worker thread is simply a ThreadPool thread. The managing BackgroundWorker creates a ManualResetEvent object for each item in the ListView. As the BackgroundWorker launches each ThreadPool thread, pass the ManualResetEvent as an argument to the QueueUserWorkItem function. Then, just before each ThreadPool thread exits, set the ManualResetEvent object.

The BackgroundWorker thread can then put all of the ManualResetEvent objects in an array and wait on that array using the WaitHandle.WaitXXX functions. As each thread finishes, you can use the BackgroundWorker's events to update the UI or you can use the Control.Invoke() technique to update the UI (see Marc Gravell's answer here).

Hope this helps.

Matt Davis
This seems like a reasonable approach if I can't figure out a message-pumping wait. I find it really hard to believe there isn't one. I'll update the thread if I find something.
jeffamaphone