My kingdom for a ThreadPool Join

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

I come from the land of Java and C++** where it is relatively easy to create
a pool of threads, send them off to a task, then call the join method and
await all of their completion. However, I cannot for the life of me figure
out how to get this relatively simple concept working in .net - specifically
C#.

I posted some code earlier where I was using ThreadPool.QueueUserWorkItem -
I couldn't figure out how to get my code to wait for the threads to finish
execution without doing some potentially dangerous coding that wouldn't
really work on a multi-processor machine (look up volatile memory for why
this is the case).

However, I read elsewhere that I could use the BeginInvoke and EndInvoke on
a delegate to address this need. However, I am having the exact same problem
as before - now using the delegate my code looks like this:
-----------------------------
MyClass myObj = new MyClass (doTask);
for (int i = start; i <= end; i++)
{
try
{
myObj.BeginInvoke (i,
new AsyncCallback (displayResultOfMethod),
i);
}
catch (Exception ex)
{
m_textBox.AppendText("An error occurred");
}
}
//would like to block here until all of the above threads have finished
-----------------------------

Can someone please show me the code I need to add to get this to work. Also
please do not dwell on these aspects of my message:
1. Thread pools and joins in C++ (see the explanation at the end of this
post as to how I did this in C++ if this is an issue for you).
2. Dangerous coding and volatile memory - in my previous post I suggested a
way I could address my need - but my suggested solution was poor since it
could cause problems in a multi-processor environment - also it wouldn't be
elogant since I would have to do polling to determine when the threads
finished.

Please just let me know what code I'm missing so I can do that simple
concept of blocking until a pool of threads have finished.

Thanks and I'm sorry if this post sounds demanding/argumentative it is just
that my experience on newsgroups is that unless you are very specific then
you will not get an answer to your problem.

Thanks,
Novice

**For C++ I had written my own library specific to a particular OS (since
the standard doesn't specify things like threads) that had a thread pool API
for joins.
 
Novice:

You are so very close.

Save the return value of BeginInvoke to call EndInvoke. EndInvoke will
block until the operation completes. EndInvoke also cleans up any goo
started with BeginInvoke, and can fetch output and return values if
need be.

A sample might look like:

class Class1
{
[STAThread]
static void Main(string[] args)
{
MyClass m = new MyClass();
DoWorkDelegate dw = new DoWorkDelegate(m.DoWork);

IAsyncResult[] asyncResults;
asyncResults = new IAsyncResult[iterations];

for(int i = 0; i < iterations; i++)
{
asyncResults =
dw.BeginInvoke(i.ToString(), null, null);
}

for(int i = 0; i < iterations; i++)
{
string result;
result = dw.EndInvoke(asyncResults);
Console.WriteLine(result);
}
}

const int iterations = 10;
}

class MyClass
{
public string DoWork(string value)
{
Console.WriteLine("Inside DoWork");
Thread.Sleep(5000);
return value;
}
}

delegate string DoWorkDelegate(string value);

HTH,
 
You might also want to take a look at IAsyncResult.WaitHandle and
WaitHandle.WaitAny() method depending on your situation.

Sijin Joseph
http://www.indiangeek.net
http://weblogs.asp.net/sjoseph



Scott said:
Novice:

You are so very close.

Save the return value of BeginInvoke to call EndInvoke. EndInvoke will
block until the operation completes. EndInvoke also cleans up any goo
started with BeginInvoke, and can fetch output and return values if
need be.

A sample might look like:

class Class1
{
[STAThread]
static void Main(string[] args)
{
MyClass m = new MyClass();
DoWorkDelegate dw = new DoWorkDelegate(m.DoWork);

IAsyncResult[] asyncResults;
asyncResults = new IAsyncResult[iterations];

for(int i = 0; i < iterations; i++)
{
asyncResults =
dw.BeginInvoke(i.ToString(), null, null);
}

for(int i = 0; i < iterations; i++)
{
string result;
result = dw.EndInvoke(asyncResults);
Console.WriteLine(result);
}
}

const int iterations = 10;
}

class MyClass
{
public string DoWork(string value)
{
Console.WriteLine("Inside DoWork");
Thread.Sleep(5000);
return value;
}
}

delegate string DoWorkDelegate(string value);

HTH,

--
Scott
http://www.OdeToCode.com

I come from the land of Java and C++** where it is relatively easy to create
a pool of threads, send them off to a task, then call the join method and
await all of their completion. However, I cannot for the life of me figure
out how to get this relatively simple concept working in .net - specifically
C#.

I posted some code earlier where I was using ThreadPool.QueueUserWorkItem -
I couldn't figure out how to get my code to wait for the threads to finish
execution without doing some potentially dangerous coding that wouldn't
really work on a multi-processor machine (look up volatile memory for why
this is the case).

However, I read elsewhere that I could use the BeginInvoke and EndInvoke on
a delegate to address this need. However, I am having the exact same problem
as before - now using the delegate my code looks like this:
-----------------------------
MyClass myObj = new MyClass (doTask);
for (int i = start; i <= end; i++)
{
try
{
myObj.BeginInvoke (i,
new AsyncCallback (displayResultOfMethod),
i);
}
catch (Exception ex)
{
m_textBox.AppendText("An error occurred");
}
}
//would like to block here until all of the above threads have finished
-----------------------------

Can someone please show me the code I need to add to get this to work. Also
please do not dwell on these aspects of my message:
1. Thread pools and joins in C++ (see the explanation at the end of this
post as to how I did this in C++ if this is an issue for you).
2. Dangerous coding and volatile memory - in my previous post I suggested a
way I could address my need - but my suggested solution was poor since it
could cause problems in a multi-processor environment - also it wouldn't be
elogant since I would have to do polling to determine when the threads
finished.

Please just let me know what code I'm missing so I can do that simple
concept of blocking until a pool of threads have finished.

Thanks and I'm sorry if this post sounds demanding/argumentative it is just
that my experience on newsgroups is that unless you are very specific then
you will not get an answer to your problem.

Thanks,
Novice

**For C++ I had written my own library specific to a particular OS (since
the standard doesn't specify things like threads) that had a thread pool API
for joins.
 
The hard part is that the 1.1 docs say that a BeginInvoke without a
matching EndInvoke could leak. Since this forces everyone to have an
EndInvoke we might as well block on EndInvoke instead of WaitOne.
 
It has been a while since I have got exactly what I asked for from a
newsgroup posting.

Unfortunately I have two further questions:
1. Why has Microsoft changed what I considered a well known threading
paradigm to a new one - using this BeginInvoke, EndInvoke pattern?

You can still use Thread.Join if you want to. Don't forget, Java (pre
v5, anyway) doesn't provide a thread pool anyway, so you'd have to
build the whole thread pool functionality - which you can do in .NET
too.
2. I just found out that you can't extend the Thread class, but instead to
get an object's method to act in a threaded manner you have to instantiate a
Thread object and pass in your object's method. Again this is a different
pattern from previous threading software API paradigms that I am familiar
with. Why the change?

It's very similar to the preferred way in Java - implementing
IRunnable. Using a delegate just gives a bit more flexibility.

I've never liked extending Thread in Java - at least, not just to tell
it what to run. The .NET way (and the IRunnable way in Java) is
cleaner, IMO. It separates the semantics of the thread itself from the
task the thread is running - and allows more flexibility in terms of
inheritence.
 
Wow - good answers.

I checked out your webpage - if you were an agnostic atheist and liked
Douglas Adams instead of Stephen King I would say you are 2 or 3 year older
version of me.

Hey, I like Douglas Adams too :)
Novice

PS Though I doubt your worms skills can be as good as mine
;)

Pah! Admittedly I haven't been following it recently, but "back in the
day" I was pretty hot at Worms. Finished the W:A missions before anyone
else on the net, as far as I know :)

(I also once got an email from Spadge asking me if I fancied a job with
T17. That might have been after I wrote a utility to allow you to play
on any picture as a level for Worms2. I sent them a screenshot - they
thought I'd faked it for a while.)
I have a screenshot I can e-mail you which may prove my point

Bring it on...
 
Would the following work, or is there a problem with this?


public class App {

static Int32 numAsyncOps;
static AutoResetEvent asyncOpsAreDone = new AutoResetEvent(false);


public static void Main() {

Interlock.Exchange(numAsyncOps, 200);

for (Int32 threadNum = 0; threadNum < 200; threadNum++) {
ThreadPool.QueueUserWorkItem(new WaitCallback(Process));
}

asyncOpsAreDone.WaitOne();
}


static void Process(Object state) {

// .....

if (Interlocked.Decrement(ref numAsyncOps) == 0)
asyncOpsAreDone.Set();
}
}


Phil..
 
Hi Phil:

Your example also works. It's one of those tradeoffs to evaluate. I
can imagine scenarios where using a single AutoResetEvent could be a
better approach. BeginInvoke / EndInvoke, at least to me, feels like
it is harder to "screw up" - it works at a higher level of
abstraction.
 
Back
Top