Multi-threading article finally "finished" - reviewers welcome

J

Jon Skeet [C# MVP]

Please excuse the cross-post - I'm pretty sure I've had interest in the
article on all the groups this is posted to.

I've finally managed to finish my article on multi-threading - at least
for the moment. I'd be *very* grateful if people with any interest in
multi-threading would read it (even just bits of it - it's somewhat
long to go through the whole thing!) to check for accuracy,
effectiveness of examples, etc.

Feel free to mail me directly with comments or post them here.

The article is at:
http://www.pobox.com/~skeet/csharp/multithreading.html
 
C

Chris Mullins

Jon Skeet said:
I've finally managed to finish my article on multi-threading - at least
for the moment. I'd be *very* grateful if people with any interest in
multi-threading would read it (even just bits of it - it's somewhat
long to go through the whole thing!) to check for accuracy,
effectiveness of examples, etc.

Feel free to mail me directly with comments or post them here.

I scanned through your article and it seemed very well written. I have a
little bit of feedback on a few sections that you may be interested in:

The section on volitile and stale data, I though the example and text was
good for beginners, but didn't touch on what was (is!) the biggest issue
there for me - that is the problem of "it runs great in debug mode, but when
I turn on optimizations my code doesn't work any more." issue. The way the
various optimizers can and do isolate variables inside loops and other very
subtle things has caught me by surprise on more than one occasion. Your
suggestion of wrapping things in a lock in order to avoid the 'volitile'
issue is excellent - especially as it'll work in VB.NET, which lacks the
volitile keyword.

The code samples in the "Stopping" section, I don't agree with. First the
Nitpicks:
You are using variables "stopping" and "stopped", and properties "Stopping"
and "Stopped". This naming convention shoud, I believe, be frowned upon.
Relying on case to differentiate members and properties is just asking for
trouble. It also violates the naming convention MS spells out in the MSDN
documentation for .NET.

I typically write this code as:

Private _stop As New Threading.ManualResetEvent(False)
Private _runningThread As Threading.Thread

Public Sub StartTheThread()
_stop.Reset()
_runningThread = New Threading.Thread(AddressOf MyThread)
_runningThread.Start()
End Sub

Public Sub StopTheThread()
_stop.Set()
_runningThread.Join()
End Sub

Private Sub MyThread()
While Not _stop.WaitOne(0, False)
' Do Work Here
End While
End Sub

I prefer this over your sample for a few reasons
1 - It is my belief (I have not benchmarked it, although I should) that
testing an event for Set/Not-Set is much cheaper than acquiring and
releasing a monitor (potentially) several millions times per second.

2 - If my thread loop doesn't have to run "as fast as it can", I can easilyl
change the to "While Not _stop.WaitOne(1000, False)" to make my loop run
once per second, while at the same time being responsive to shutdown events.
In your sample code, I would need to use a Sleep to slow down the loop,
which makes the thread unresponsive to shutting down.

3 - Your code is, in essece, creating a Manual Reset Event. Why create
something that's already there?


There were a few sections that I would have liked to see in there - mostly
these are questions that I've had for a while, and haven't ever been able to
get good ansers to..

1 - Something that I've looked for information on, and found absolutly
nothing, is the "Synchronized" version of the various collection classes. I
have ended up having to roll my own collections in many cases, as I need to
access them from multiple threads (I am sooooo looking forward to
Generics!). With the lack of documentation on the synchronized collection
classes, I was never comfortable using them. What about them is thread safe?
I'm pretty sure Iteration is not (although it could be - the iterator could
grab a lock, and prevent other iterators from proceeding until it's
complete). Hashtables say (somewhere) that "one writer and multiple readers"
is thread safe, but I've never been quite sure of that. What about the other
collections?

2 - Some of the Win32 threading constructs that people have been using for
so long are not present in .NET. Specifically Semaphores and (I think) Named
Events. Any idea why?

3 - Some suggestions on how to start debugging threaded code. These could be
simple suggestions like "Give all your threads unique names, so that then
you're looking at the Threads window in the debugger, you can quickly tell
which thread is which", or complex suggestions like "Use SoS to determine
which thread is holding a lock".

4 - You don't have a section on Events (either Manual or AutoReset). Along
with Monitors, these are the most used threading constructs.

5 - ReaderWriterLocks are handy at times, but are probably beyond the scope
of your article.

6 - Another advanded topic that I've seen little on, but seems as if it
could be really usefull, is the ability of the Threadpool to have a Handle
bound to it, and provide callbacks when this handle changed. Can I bind
standard wait handles to the thread pool so that I can callbacks whenever a
manual or auto-reset even is changed? It seems as if there would probably be
some fascinating use cases for this...
 
G

Guest

Very nice article; had a quick look through it, its an easy way to explain
not-so-easy issues :)

Back in the VB days everybody wanted multi-threads (even did it with api
*highly unstable*) but now I don´t see people using it as much on .NET as it
would seem natural to.

I myself had a time and half on a multi-threading application on .NET where
I learned just how messy can it get without some sort of mutex.
 
G

Greg Young

A good addition might be a discussion of ManualResetEvent and AutoResetEvent
especially the differences between them and when they are appropriate ... I
get questions on that all the time.

Greg
 
J

Jon Skeet [C# MVP]

Greg Young said:
A good addition might be a discussion of ManualResetEvent and AutoResetEvent
especially the differences between them and when they are appropriate ... I
get questions on that all the time.

Right. That's two requests for them: they're definitely going in. This
is a good opportunity to get myself more thoroughly familiar with them,
too :)
 
J

Jon Skeet [C# MVP]

Very nice article; had a quick look through it, its an easy way to explain
not-so-easy issues :)

Cool, thanks :) As with most of the articles, it was born out of
laziness: I don't want to spend ages typing the same kinds of answer
out again and again!
Back in the VB days everybody wanted multi-threads (even did it with api
*highly unstable*) but now I don´t see people using it as much on .NET as it
would seem natural to.

Interesting. I certainly cringe when Application.DoEvents is
recommended for something which naturally lends itself to multiple
threads.
I myself had a time and half on a multi-threading application on .NET where
I learned just how messy can it get without some sort of mutex.

I would laugh, but the memory of similar situations is too painful ;)
 
J

Jon Skeet [C# MVP]

Chris Mullins said:
I scanned through your article and it seemed very well written. I have a
little bit of feedback on a few sections that you may be interested in:

The section on volitile and stale data, I though the example and text was
good for beginners, but didn't touch on what was (is!) the biggest issue
there for me - that is the problem of "it runs great in debug mode, but when
I turn on optimizations my code doesn't work any more." issue. The way the
various optimizers can and do isolate variables inside loops and other very
subtle things has caught me by surprise on more than one occasion. Your
suggestion of wrapping things in a lock in order to avoid the 'volitile'
issue is excellent - especially as it'll work in VB.NET, which lacks the
volitile keyword.

I can't work out whether I'm surprised that VB.NET lacks volatile or
not - I think I *may* have tried to find an equivalent and failed, but
I'm not sure.

It's a good point though - I think I've specified somewhere that "it
works for me" isn't a good enough reason to believe the code is valid,
but I'll emphasise it much more. Good catch.
The code samples in the "Stopping" section, I don't agree with. First the
Nitpicks:
You are using variables "stopping" and "stopped", and properties "Stopping"
and "Stopped". This naming convention shoud, I believe, be frowned upon.
Relying on case to differentiate members and properties is just asking for
trouble. It also violates the naming convention MS spells out in the MSDN
documentation for .NET.

It doesn't - the naming convention MS uses specifically doesn't mention
private members. It's not a problem for VB users because anyone outside
the class doesn't see the variables at all.

I've used the convention for years in both Java and C# and *never* had
a problem with it as far as I can remember. I find code written with my
convention significantly easier to use than code which uses underscores
all over the place - they just look horribly ugly to me, and disturb my
train of thought when I'm reading.

I'm afraid I'll stick with my convention as I do for all my code
samples.
I typically write this code as:

Private _stop As New Threading.ManualResetEvent(False)
Private _runningThread As Threading.Thread

Public Sub StartTheThread()
_stop.Reset()
_runningThread = New Threading.Thread(AddressOf MyThread)
_runningThread.Start()
End Sub

Public Sub StopTheThread()
_stop.Set()
_runningThread.Join()
End Sub

Private Sub MyThread()
While Not _stop.WaitOne(0, False)
' Do Work Here
End While
End Sub

I prefer this over your sample for a few reasons
1 - It is my belief (I have not benchmarked it, although I should) that
testing an event for Set/Not-Set is much cheaper than acquiring and
releasing a monitor (potentially) several millions times per second.

That's a heck of an assumption, in my view. Rather than making any
assumptions, I decided to test it. The main code in both my tests was
the same:

using System;
using System.Threading;

public class LockTest
{
static void Main()
{
Worker worker = new Worker();
new Thread(new ThreadStart(worker.Run)).Start();
Thread.Sleep(10000);
worker.Stop();
}
}

The worker object for my version is as on the website (except with
stopLock declared as object, not bool - oops! Fixed the website now)
but with a long counter variable which is just incremented in the loop
in the same way as with the code below, which is a slightly simplified
version of what you posted (just for the purposes of this test):

public class Worker
{
long counter=0;

ManualResetEvent stop = new ManualResetEvent(false);

public void Stop()
{
stop.Set();
}

public void Run()
{
DateTime start = DateTime.Now;
while (!stop.WaitOne(0, false))
{
counter++;
}
DateTime end = DateTime.Now;
Console.WriteLine
("Count per second: {0}", counter/(end-start).TotalSeconds);
}
}

Results (3 tests each):

Using a lock:
Count per second: 28038249.614792
Count per second: 28113891.7558685
Count per second: 27467033.4397496

Using a manual reset event:
Count per second: 1087057.6
Count per second: 1086289.82785602
Count per second: 1082087.3

So on average, using a lock we're able to count about 25 times as fast.

Just another example of threading not being a good thing to guess about
:)

I'd be very interested to see whether you get the same kind of results
- it may *very* well depend to a very large extent on the CPU(s) of the
test machines. Mine is a P4/3.06GHz laptop; no hyperthreading or
anything like that. I'd be particularly interested to know the numbers
on a dual processor machine...
2 - If my thread loop doesn't have to run "as fast as it can", I can easilyl
change the to "While Not _stop.WaitOne(1000, False)" to make my loop run
once per second, while at the same time being responsive to shutdown events.
In your sample code, I would need to use a Sleep to slow down the loop,
which makes the thread unresponsive to shutting down.

Well, I'd probably use Monitor.Wait in that case, myself. I'm happier
with Monitor than reset events, but either would work fine here. I
wouldn't usually limit it artificially like that though - normally if
there's a reason to slow something down, that's because it hasn't got
work the whole time - and there I'd use a work queuing system. If I
want a thread to essentially be at a lower priority, I'll just lower
the priority. (Ah - another thing I haven't covered :)
3 - Your code is, in essece, creating a Manual Reset Event. Why create
something that's already there?

It's not, really. There's much more to events than just testing and
setting, as you've already shown with WaitOne - there are also calls to
wait for potentially many events at a time, etc. I believe testing a
boolean (even in a lock) is significantly simpler and easier to
understand than ManualResetEvents, which is why I stick with them in
general.
There were a few sections that I would have liked to see in there - mostly
these are questions that I've had for a while, and haven't ever been able to
get good ansers to..

I'll present quick answers here (to a couple of them), and see if there
are other comments in this thread (no pun intended). I'll then see
which bits are appropriate for inclusion in the article itself.
1 - Something that I've looked for information on, and found absolutly
nothing, is the "Synchronized" version of the various collection classes. I
have ended up having to roll my own collections in many cases, as I need to
access them from multiple threads (I am sooooo looking forward to
Generics!). With the lack of documentation on the synchronized collection
classes, I was never comfortable using them. What about them is thread safe?
I'm pretty sure Iteration is not (although it could be - the iterator could
grab a lock, and prevent other iterators from proceeding until it's
complete). Hashtables say (somewhere) that "one writer and multiple readers"
is thread safe, but I've never been quite sure of that. What about the other
collections?

I believe the idea of synchronized collections is that each individual
operation automatically takes out a lock, but that in order to
synchronize a whole series of operations, you need to lock on the
SyncRoot of the collection.

I've seen the same statement about multiple readers and a single writer
for hashtable, but I haven't tried to verify it with stress testing or
anything like that.
2 - Some of the Win32 threading constructs that people have been using for
so long are not present in .NET. Specifically Semaphores and (I think) Named
Events. Any idea why?

I really don't know. Semaphores are handy constructs, and fairly easily
built out of monitors (so long as you're careful :) I may present a
sample semaphore class for those who are interested. I wouldn't be at
all surprised if they made it into .NET v2 anyway though.
3 - Some suggestions on how to start debugging threaded code. These could be
simple suggestions like "Give all your threads unique names, so that then
you're looking at the Threads window in the debugger, you can quickly tell
which thread is which", or complex suggestions like "Use SoS to determine
which thread is holding a lock".

Right, that's a good idea.
4 - You don't have a section on Events (either Manual or AutoReset). Along
with Monitors, these are the most used threading constructs.

Funnily enough, I've virtually never used them - except to build a
fuller Monitor implementation for the Compact Framework :)

I suspect it's my Java background showing through to some extent, but I
more naturally think in terms of monitors, and they tend to do
everything I need them to. I think they're generally simpler, which is
another reason I use them :) (I do use Events when I want to wait for
multiple conditions etc.)
5 - ReaderWriterLocks are handy at times, but are probably beyond the scope
of your article.

Not sure - I think that's a very good idea. I haven't had to use them
myself, but almost certainly will at some time. I'll take a bit of a
breather and then probably add a section about them.
6 - Another advanded topic that I've seen little on, but seems as if it
could be really usefull, is the ability of the Threadpool to have a Handle
bound to it, and provide callbacks when this handle changed. Can I bind
standard wait handles to the thread pool so that I can callbacks whenever a
manual or auto-reset even is changed? It seems as if there would probably be
some fascinating use cases for this...

Mmm... I really don't know *anything* about that topic. Sounds like
something it would be worth investigating...
 
C

Chris Mullins

Jon Skeet said:
I can't work out whether I'm surprised that VB.NET lacks volatile or
not - I think I *may* have tried to find an equivalent and failed, but
I'm not sure.

I've looked several times for it, and each time been quite shocked not
to find it. I always feel if I dig "just a bit deeper" I'll find it. Ah
well.
One more thing that occasionally forces me to write code in C#...
You are using variables "stopping" and "stopped", and properties "Stopping"
and "Stopped". This naming convention shoud, I believe, be frowned upon.
[...]

I've used the convention for years in both Java and C# and *never* had
a problem with it as far as I can remember.
I'm afraid I'll stick with my convention as I do for all my code
samples.

'Fair Nuff. I still think it's evil though.
I prefer this over your sample for a few reasons
1 - It is my belief (I have not benchmarked it, although I should) that
testing an event for Set/Not-Set is much cheaper than acquiring and
releasing a monitor (potentially) several millions times per second.

That's a heck of an assumption, in my view. Rather than making any
assumptions, I decided to test it.
[...]

Results (3 tests each):

Using a lock:
Count per second: 28038249.614792
Count per second: 28113891.7558685
Count per second: 27467033.4397496

Using a manual reset event:
Count per second: 1087057.6
Count per second: 1086289.82785602
Count per second: 1082087.3

So on average, using a lock we're able to count about 25 times as fast.

Wow. I should know better by now than to make assumptions on these
things. That's what Compuware's profiler is for.
I believe the idea of synchronized collections is that each individual
operation automatically takes out a lock, but that in order to
synchronize a whole series of operations, you need to lock on the
SyncRoot of the collection.

I'm pretty sure this is what they do too, but I've never seen this actually
documented anywhere. Their complete non-existance on the CF has meant
that I needed to write my own thread-safe collections anyway, so I've
never looked into them in great detail. (But for a threading article on the
standard CLR, I think they're a good topic)
I really don't know. Semaphores are handy constructs, and fairly easily
built out of monitors (so long as you're careful :) I may present a
sample semaphore class for those who are interested. I wouldn't be at
all surprised if they made it into .NET v2 anyway though.

The one thing that Semaphores have, that I don't think you can duplicate
with Monitors, is that they're cross-process. They're really handy for "Is
my application already running?" checks, as well as a wide variety of
other computer-wide resource management tricks.
Funnily enough, I've virtually never used them - except to build a
fuller Monitor implementation for the Compact Framework :)

That's funny - I used a combination of Win32 calls and Monitors to
implement a full ManualResetevent on the compact framework.

For some silly reason there is no WaitHandle.WaitOne(Timeout, false)
overload on the CF, which makes the class pretty useless for a wide
vareity of useses.. It's either wait forever, or don't wait at all. If
you want the source to this, drop me an email some time.

(That's the least I can do for you writing that UTF32String class a few
weeks back)
 
J

Jon Skeet [C# MVP]

Chris Mullins said:
I've looked several times for it, and each time been quite shocked not
to find it. I always feel if I dig "just a bit deeper" I'll find it. Ah
well.
One more thing that occasionally forces me to write code in C#...

Reflector decompiles a volatile variable as having ModReq(IsVolatile)
after it, which I believe is what's in IL. It doesn't look like you can
apply that within VB though.

I'm pretty sure this is what they do too, but I've never seen this actually
documented anywhere. Their complete non-existance on the CF has meant
that I needed to write my own thread-safe collections anyway, so I've
never looked into them in great detail. (But for a threading article on the
standard CLR, I think they're a good topic)

Right. I might see what else I can dig up about them - without the
source code being available, it's hard to say. I can always look at the
Rotor implementation, I suppose.
The one thing that Semaphores have, that I don't think you can duplicate
with Monitors, is that they're cross-process. They're really handy for "Is
my application already running?" checks, as well as a wide variety of
other computer-wide resource management tricks.

Ah - I've been thinking in terms of the computer science idea of a
counting semaphore, rather than the Win32 specific concept.

For cross-process "am I running" checks, however, a Mutex works pretty
well. See
http://www.pobox.com/~skeet/csharp/faq/#one.application.instance

I dare say there are other uses which Mutex wouldn't cut it for though.
That's funny - I used a combination of Win32 calls and Monitors to
implement a full ManualResetevent on the compact framework.

For some silly reason there is no WaitHandle.WaitOne(Timeout, false)
overload on the CF, which makes the class pretty useless for a wide
vareity of useses.. It's either wait forever, or don't wait at all. If
you want the source to this, drop me an email some time.

Have you thought about contributing it to OpenNETCF? That's what I did
with what is now called MonitorEx. I had the same problem as you did
though - I can't implement Wait with a timeout. I suspect if either of
us could implement one of them, we could use it to implement the other
:)

(I had a few ideas about how to do it using timers, but the ideas
became pretty horrible.)
(That's the least I can do for you writing that UTF32String class a few
weeks back)

Ah, that was for you, was it? I couldn't remember. Did you ever use it,
or were you able to make do with a couple of bits of it? It was fun
writing it either way :) (I dread to think what that says about me...)
 
J

Jon Skeet [C# MVP]

Brian Gideon said:
It's been a while since I've monitored usenet, but with this slick
web-based interface at the MSDN site I might be a frequent visitor.

I think I'll always favour a "proper" newsreader app myself, but each
to their own :)
Anyway, multithreaded applications have always interested me so your
post naturally stuck out like a sore thumb. You have a very nice
article and coming from you I think we can all count on quality
information. Nice job!

Thanks - but until it's been vetted by a few people who know more than
I do, I wouldn't assume absolutely everything's right. I've tried to be
as accurate as I can, but as I state at the start of the article, I'm
far from being an expert on it. Trouble is, I don't want to bother the
real experts too much by asking them to look at it :)
 
C

Chris Mullins

[UTF32 String Class]
Ah, that was for you, was it? I couldn't remember. Did you ever use it,
or were you able to make do with a couple of bits of it? It was fun
writing it either way :) (I dread to think what that says about me...)

Unfortunatly I ended up not being able to use it, although I spent quite
some time with it before coming to that conclusion.

I needed it to perform StringPrep for some XMPP stuff, and some of the
required steps for that are pretty ugly.

The two steps that specifically made me decide not to implement the RFC
myself were the cannocial form transforms, and the KC Normalization step. I
couldn't for the life of me figure out a reliable and space-efficient way to
get all the Unicode Data tables required for that into a usable form.
They're all available for download on the Unicode site, but it's like 60
megs of data, and I really, really wasn't looking forward to writing a perl
script of some kind to transform them into .NET resource files and the like.
It was a nightmare.

I did end up learning more about Unicode than I ever wanted to know, that's
for sure!

I think I've finally settled on wrapping 'libidn' (which is a LGPL licensed
project) in a Win32 DLL, and calling that. Ick.
 
D

Daniel O'Connell [C# MVP]

Results (3 tests each):
Using a lock:
Count per second: 28038249.614792
Count per second: 28113891.7558685
Count per second: 27467033.4397496

Using a manual reset event:
Count per second: 1087057.6
Count per second: 1086289.82785602
Count per second: 1082087.3

So on average, using a lock we're able to count about 25 times as fast.

Just another example of threading not being a good thing to guess about
:)

I'd be very interested to see whether you get the same kind of results
- it may *very* well depend to a very large extent on the CPU(s) of the
test machines. Mine is a P4/3.06GHz laptop; no hyperthreading or
anything like that. I'd be particularly interested to know the numbers
on a dual processor machine...

The numbers are a bit better on my dual processor machine, but not
substantially. Looks like lock is about 10x faster on this machine.
I don't think that these results would be sufficent to state that the
differences are due to multiple processor machines so much as difference in
speeds between the processors I used and the one you used. I ran this on a
dual 2.2 ghz xeon, with hyperthreading. I was able to verify that the speed
of locks and events are as identical as benchmarks can be when affinity
targets one or two physical processors, or all four virtual processors,
however. I would guess that the speed of these sync mechanisms are pretty
much neutral to the number of processors as long as their is only one
thread. A more interesting, but more complicated, test would be to test lock
and event speed across multiple threads.

Using a lock:
Count per second: 5581104.27543036
Count per second: 5615276.9
Count per second: 5500714.86697966

Using a manual reset event:
Count per second: 500654.6
Count per second: 489649.3771518
Count per second: 494306.7
 
S

Simon Smith

A newsreader app is ideal, but when the outgoing NNTP port is closed you
have limited options.


<Shameless Puff - apologies>

NewsLook has the ability to delegate the calls to the NNTP server via
an HTTP call over port 80 to it's home site. Currently it's sloow as I've
not been concentrating on that part of it. If there's interest though....



Simon Smith
simon dot s at ghytred dot com
http://www.ghytred.com/NewsLook - Usenet for Outlook
 
G

Guest

Please please please split it out into multiple html pages - one long one is horrible.

Do you keep your .cs code files like that? No, I didn't think so! HTML deserves the same respect and for exactly the same reason, same goes for anyone reading it.
 
G

Guest

"triple-new" syntax is one of the great features of C# - check out:

(new Thread(new ThreadStart((new HistoricalCatchup( accessdb, drive)).StartCatchup))).Start();

an example of mine that starts a thread on a member function of a class (due to the fact that it has to have the parameters accessdb and drive)
 
J

Jon Skeet [C# MVP]

Beeeeeeeeeeeeves said:
"triple-new" syntax is one of the great features of C# - check out:

(new Thread(new ThreadStart((new HistoricalCatchup(accessdb,
drive)).StartCatchup))).Start();

an example of mine that starts a thread on a member function of a
class (due to the fact that it has to have the parameters accessdb
and drive)

Of course, there's nothing *forcing* you to do that all on one line -
you could easily split it up.
 
J

Jon Skeet [C# MVP]

Beeeeeeeeeeeeves said:
Please please please split it out into multiple html pages - one long
one is horrible.
Agreed.

Do you keep your .cs code files like that? No, I didn't think so!
HTML deserves the same respect and for exactly the same reason, same
goes for anyone reading it.

The trouble is, it started off being a relatively short article, which
was fine as one page. It's definitely too long now. I'll work out
exactly how to split it up soon.
 
S

Stefano \WildHeart\ Lanzavecchia

Beeeeeeeeeeeeves said:
Please please please split it out into multiple html pages - one long one is horrible.

Do you keep your .cs code files like that? No, I didn't think so! HTML
deserves the same respect and for exactly the same reason, same goes for
anyone reading it.

It's easier to print it that way, though. Do you split your WinWord
documents page per page?
 
J

Jon Skeet [C# MVP]

Stefano "WildHeart" Lanzavecchia said:
It's easier to print it that way, though. Do you split your WinWord
documents page per page?

I can always provide a print version which is just the concatenation of
all the other pages - I think that's what most sites do.
 
K

Kiran

Jon Skeet,

Its some good work u have in there. you have almost covered all the
technical aspect that goes in with handling the thread. I have already give
a print!!.

Having said this, I'll like to add that, I generally like to treat a Thread
as an fully self managed Object rather than a method of an object that is
used by thread(so to say...). OK now I am confusing... what I mean is(more
of a design issue), in every example I see, there are code written like
this:

ThreadStart job = new ThreadStart(myobj.ThreadJob);
Thread thread = new Thread(job);
thread.Start();

well there is nothing wrong with this, but I like to see something like

MyThread thread = new MyThread();

this makes my design lot cleaner to understand, How I do this is something
like this.

class abstract ThreadBase
{
<< events for OnThreadStart, OnThreadDone, OnXXX>>
void abstract Run();
protected virtual void OuterRun()
{
<< trigger OnStartEvent>>
try { Run(); }
catch(...){<<handle Exception & raise events>>}
<< trigger OnThreadDoneEvent>>
}
public ThreadBase()//constructor
{
ThreadStart job = new ThreadStart(OuterRun);
Thread thread = new Thread(job);
thread.Start();
}
}


this way the method that is run in the thread & the thread itself are
treated as from single object. and I have lot of common functionality in the
ThreadBase so that I don't have to re write it for every time I want to use
a thread.

all I have to do for creating a new thread functionality is derive a class
from ThreadBase and override its Run() method and other OnXXX method.

I may be biased here with this approach as I come form Delphi background,
but I have not found much issue with it so far.

Regards
Kiran
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top