From: Hector Santos on
For the longest, for my non-I/O based thread work, I used
WaitForMultiObjects (WFMO) as a way to wait for a set of worker
threads to complete, simpling by putting the thread handles in an
array and passing it to WFMO, for example:

// Wait (infinitely) for 10 threads to ALL complete.

HANDLE hThreads[10] = {0};

for(int i=0; i<10; i++) {
hThreads[i] = CreateThread(.......);
}

WFMO(hThreads,10,TRUE,INFINITE);

I wish to do the same in C#, I can start the threads, but I don't see
a simple WFMO() idea.

Ideally, I wish to have a callback version of WFMO() so that an event
is called (i.e. a OnThreadsFinish() event) signally when all threads
are finished.

Note: I was able to come up with a method, but it seems there is a
more natural way in .NET. What I do is:

1) Create X BackgroundWorkers and put it into an array Workers[]

2) Then have a DoEvents loop:

int done = 0;
while (done < X)
{
done = 0;
for (int i=0; i < X; i++) {
if (!Workers[i].IsBusy) done++;
}
Application.DoEvents();
}

// THREADS WE DONE - do whatever

I only used a Thread Pool. But I don't see a function there to
determine when all the queued threads are complete.

Thanks

--
HLS
From: Tom Shelton on
Hector Santos wrote :
> For the longest, for my non-I/O based thread work, I used WaitForMultiObjects
> (WFMO) as a way to wait for a set of worker threads to complete, simpling by
> putting the thread handles in an array and passing it to WFMO, for example:
>
> // Wait (infinitely) for 10 threads to ALL complete.
>
> HANDLE hThreads[10] = {0};
>
> for(int i=0; i<10; i++) {
> hThreads[i] = CreateThread(.......);
> }
>
> WFMO(hThreads,10,TRUE,INFINITE);
>
> I wish to do the same in C#, I can start the threads, but I don't see a
> simple WFMO() idea.
>
> Ideally, I wish to have a callback version of WFMO() so that an event is
> called (i.e. a OnThreadsFinish() event) signally when all threads are
> finished.
>
> Note: I was able to come up with a method, but it seems there is a more
> natural way in .NET. What I do is:
>
> 1) Create X BackgroundWorkers and put it into an array Workers[]
>
> 2) Then have a DoEvents loop:
>
> int done = 0;
> while (done < X)
> {
> done = 0;
> for (int i=0; i < X; i++) {
> if (!Workers[i].IsBusy) done++;
> }
> Application.DoEvents();
> }
>
> // THREADS WE DONE - do whatever
>
> I only used a Thread Pool. But I don't see a function there to determine
> when all the queued threads are complete.
>
> Thanks

I think you might be lookign for hte WaitHandle.WaitAll method?

--
Tom Shelton


From: Hector Santos on
Tom Shelton wrote:

>> I only used a Thread Pool. But I don't see a function there to
>> determine when all the queued threads are complete.
>>
>> Thanks
>
> I think you might be lookign for hte WaitHandle.WaitAll method?


Yes, thanks tom. I had missed it somehow in MSDN jumping all over the
place and got side tracked with MSDN examples with a MSDN comment
regarding "multi-tasking" behavior on single vs multi-processor/core
machines. I have to pencil that and go over that before I complete my
work.

But I had finally found it at this "Threading in C#" web site with
excellent summary background information for people like me. All
concepts consolidated right at the top! BOOK MARK IT! :)

http://www.albahari.com/threading/part3.aspx

MSDN threading pages also has some needed background information
regarding performance.

What I ended up doing is writing a class that spawns the dynamically
allocated workers with an additional optional thread to monitor the
completion and fire an OnMultiThreadComplete event. The default is to
just wait in the calling thread with a function that does the loop I
showed in my last post. That works nicely as well.

BTW, I found the ultimate MSDN Online Help GUI - CHROME!!! IE is just
too slow and it is superior with the "smart auto search" as you type.
Seems like GOOGLE indexed the entire MSDN content! Check it out!
Honestly, it isn't so bad now. THe IDE help simply sucks. But with
CHROME it is so fast that its like the old VC6 MSDN but better because
the #1 problem there was not being able to open many help page
instances. Any way, thats a different topic. :)


-- Coming soon, WCLEX - Wildcat! Live Exchange!
HLS
From: Tom Shelton on
Hector Santos wrote on 6/1/2010 :
> Tom Shelton wrote:
>
>>> I only used a Thread Pool. But I don't see a function there to determine
>>> when all the queued threads are complete.
>>>
>>> Thanks
>>
>> I think you might be lookign for hte WaitHandle.WaitAll method?
>
>
> Yes, thanks tom. I had missed it somehow in MSDN jumping all over the place
> and got side tracked with MSDN examples with a MSDN comment regarding
> "multi-tasking" behavior on single vs multi-processor/core machines. I have
> to pencil that and go over that before I complete my work.
>
> But I had finally found it at this "Threading in C#" web site with excellent
> summary background information for people like me. All concepts consolidated
> right at the top! BOOK MARK IT! :)
>
> http://www.albahari.com/threading/part3.aspx
>
> MSDN threading pages also has some needed background information regarding
> performance.
>
> What I ended up doing is writing a class that spawns the dynamically
> allocated workers with an additional optional thread to monitor the
> completion and fire an OnMultiThreadComplete event. The default is to just
> wait in the calling thread with a function that does the loop I showed in my
> last post. That works nicely as well.
>
> BTW, I found the ultimate MSDN Online Help GUI - CHROME!!! IE is just too
> slow and it is superior with the "smart auto search" as you type. Seems like
> GOOGLE indexed the entire MSDN content! Check it out! Honestly, it isn't so
> bad now. THe IDE help simply sucks. But with CHROME it is so fast that its
> like the old VC6 MSDN but better because the #1 problem there was not being
> able to open many help page instances. Any way, thats a different topic. :)
>
>
> -- Coming soon, WCLEX - Wildcat! Live Exchange!
> HLS

I'm glad you got it worked out. As for using Chrome - no thanks. I'll
stick to firefox. May not be as fast, but IMHO, Google is the current
evil empire :)

--
Tom Shelton


From: Peter Duniho on
Tom Shelton wrote:
> Hector Santos wrote :
>> For the longest, for my non-I/O based thread work, I used
>> WaitForMultiObjects (WFMO) as a way to wait for a set of worker
>> threads to complete, simpling by putting the thread handles in an
>> array and passing it to WFMO, for example:
>>
>> // Wait (infinitely) for 10 threads to ALL complete.
>>
>> HANDLE hThreads[10] = {0};
>>
>> for(int i=0; i<10; i++) {
>> hThreads[i] = CreateThread(.......);
>> }
>>
>> WFMO(hThreads,10,TRUE,INFINITE);
>>
>> I wish to do the same in C#, I can start the threads, but I don't see
>> a simple WFMO() idea.
>>
>> [...]
>
> I think you might be lookign for hte WaitHandle.WaitAll method?

Hector probably would think that's the right equivalent to what he's
used to.

However, IMHO it is a good idea to get used to using the .NET-native
threading and synchronization techniques where applicable.

In this particular example, this means a few things:

• Don't block the GUI thread. In other words, the very design idea
of waiting on all the worker threads is fundamentally flawed.

• Use the features built into BackgroundWorker to track and respond
to changes in the active thread count.

• In other cases, use the Monitor class for cross-thread signaling.

The first two points go together, in that using the BackgroundWorker
correctly means that the GUI thread does not wind up blocked. Here's an
example:

void RunWorkers(int count)
{
for (int i = 0; i < count; i++)
{
BackgroundWorker worker = new BackgroundWorker();
int delay = i * 500;

worker.DoWork += (sender, e) =>
{
// dummy work
Thread.Sleep(delay);
};

worker.RunWorkerCompleted += (sender, e) =>
{
// Signal completion
if (--count == 0)
{
AllWorkersDone();
}
};

worker.RunWorkerAsync();
}
}

void AllWorkersDone()
{
// do whatever here
}

Note that the above assumes RunWorkers() is being called on the main GUI
thread. Which means that each RunWorkerCompleted event handler is also
executed on the main GUI thread. This has a couple of useful effects:

• The "count" variable, used directly in RunWorkers() and as a
captured variable in the RunWorkerCompleted event handlers, is only ever
used in a single thread, ensuring synchronization.

• The AllWorkersDone() method itself will be executed on the main GUI
thread, just as if the original method had gotten stuck in a loop
waiting for the threads to complete.

Of course, the big difference being that the main GUI thread doesn't
wind up blocked as in the original implementation.

Pete