Multi-threading article finally "finished" - reviewers welcome

V

Valery Pryamikov

AFIK, every primitive is
ultimately based on a spin lock at the lowest level.
If we talk about kernel mode Win32 synchronization objects - than it's not
quite so.
Yes, spin lock is used by code, but it is different in two ways:
- When thread scheduler sees that thread is waiting on Win32 synchronization
objects it immediately schedules context switch to another runnable thread
instead of wasting time spinning.

- Additionally, kernel mode spin lock sets idle bit on interrupt command
register (on Intel) or use other means (on other processor types) to notify
processor that thread is running idle operation. Interrupt command register
and this bit is not accessible from the user mode.


-Valery.
http://www.harper.no/valery
 
V

Valery Pryamikov

It's best to rely on Win32 synchronization objects, because they know how to
handle idle operations.
For example: when thread scheduler sees that thread is waiting on Win32
synchronization objects it immediately schedules context switch to another
runnable thread instead of wasting time spinning.

Additionally, kernel mode spin lock sets idle bit on interrupt command
register (on Intel) or use other means (on different processor types) to
notify processor that thread is running idle operation. Interrupt command
register and this bit is not accessible from the user mode.



-Valery.

http://www.harper.no/valery
 
W

William Stacey [MVP]

My second implementation uses system autoresetevent for the wait, so this
should not be an issue.
 
W

William Stacey [MVP]

On a single processor machine the spinning
is a waste of processor time,

Not if you do a wait or sleep(0) it is not. That gives the other thread a
chance to give up the lock, is which is exactly what you want.
 
S

Scott Allen

Not if you do a wait or sleep(0) it is not. That gives the other thread a
chance to give up the lock, is which is exactly what you want.

I guess it depends on your definition of spinlock.

If spinning means "do not preempt me because I know the lock will be
free any nanosecond now", then spinlocks are about locking CPUs, not
threads, and there wouldn't be any point in chewing up cycles on a
uni-proc system.

If spinning means "try once then yield and repeat", then I'm not sure
what benefit there is actually. I'd have to test this one out quite a
bit to be comfortable with it!
 
W

William Stacey [MVP]

If spinning means "do not preempt me because I know the lock will be
free any nanosecond now", then spinlocks are about locking CPUs, not
threads, and there wouldn't be any point in chewing up cycles on a
uni-proc system.

Agreed. On a single cpu, there is no benefit in a *busy-wait as you will
spin for rest of slice as you can't regain the lock anyway until you give up
your slice. Event on a mult-proc, I would not use busy-wait but would still
sleep unless you are tuning for something very specific.
If spinning means "try once then yield and repeat", then I'm not sure
what benefit there is actually. I'd have to test this one out quite a
bit to be comfortable with it!

Benefit is the idea that in general, the lock will be held for only a few
instruction, so do upgrade to monitor or event until you try X times
(sleeping each time to give other thread a chance to release the lock.) In
the general case, there there is lock contention, then you should get at
very next cycle. If you spin/sleep X times, then owner must be blocked on
long operation so upgrade to waiting on a monitor or event. Please test and
reply if bug or error. More of a thing to learn from as using a Monitor is
probably better in most cases.
 
J

Jon Skeet [C# MVP]

TT (Tom Tempelaere) <"=?Utf-8?B?VFQgKFRvbSBUZW1wZWxhZXJlKQ==?=" <_|\|_0
$P@|/\|titi____AThotmail.com|/\|@P$0_|\|_> said:
If you are going to write an article on threading, events are a must
(ManualResetEvent and AutoResetEvent). There are situations in which
these more natural to use and more to the point. Plus if you don't
use events, you can't wait on multiple objects (unless you use Mutex
directly instead of Monitor or lock).

Yup - I'll include them when I have some time. (That won't be for a
while - I'm moving house next week.)
If I wouldn't have these event classes and the WaitHandle.WaitAny or
WaitHandle.WaitAll functions, I would have a lot of trouble
implementing the kernel I am now writing. Without the event classes
it would at least be a lot more complex to write (IMHO) and pbbl be
less efficient (although you can't just say that, one should test
that).

They're certainly useful, but I don't think they should usually be used
when simpler constructs (like Monitor) do just as well. Go for the
simplest option, I reckon :)
 
J

Jon Skeet [C# MVP]

TT (Tom Tempelaere) <"=?Utf-8?B?VFQgKFRvbSBUZW1wZWxhZXJlKQ==?=" <_|\|_0
$P@|/\|titi____AThotmail.com|/\|@P$0_|\|_> said:
When I declare a locking object, I always make it readonly (or const
if static) to highlight the fact that the object it refers to will
not change.

Now why didn't I think of that? Excellent idea.
In the producer-consumer class, you could just lock on the queue as
well. Saves one object from memory. The queue object is an internal
state object and no reference to it is passed out of the
producer-consumer context (ie private).

But you don't know for sure whether something within Queue locks on
"this" itself. While that wouldn't be disastrous in this case, I think
it's a simpler policy to never lock on anything that isn't either
private to the class itself and used for nothing but locking, or
something which is explicitly exposed for locking purposes.
You could highlight the fact that Monitor.Enter and Montor.Exit
introduce memory barriers. You mention it only after explaining
Monitor wrt stale data (As of .NET 1.1 there is another way to
introduce a memory barrier ...).

I think that's the right place to mention it though - if I talked about
memory barriers before talking about what they really are, it could get
very confusing. Maybe I could mention them with a link to the
volatility section...
A little further in the same paragraph you mention the possible
introduction of "read barriers" and "write barriers". Check
Thread.VolatileRead and Thread.VolatileWrite. They don't introduce a
global barrier, but they do so for the variable that needs to be read
or written to (if I understood the docu correctly).

Mmm... the docs really aren't clear. I *suspect* they actually execute
a "real" volatile read/write as per the memory model, but it's hard to
say for sure. I'll mention them in an "unsure" kind of way...
There is not a single word about Thread.Interrupt, what it does and
how it should be used. The same is true for Thread.Abort. I think
these are important and deserve some explanation.

Possibly. I personally think they should be avoided at almost all
costs, but I suppose mentioning that wouldn't be a bad idea :)
 
J

Jon Skeet [C# MVP]

TT (Tom Tempelaere) <"=?Utf-8?B?VFQgKFRvbSBUZW1wZWxhZXJlKQ==?=" <_|\|_0
$P@|/\|titi____AThotmail.com|/\|@P$0_|\|_>> wrote:

[Deriving from thread or not]
What is true for Java isn't necessarily true for other languages.

True - but this is more of a general design issue rather than something
particularly language-specific.
But apart from that, a while ago when I needed threading in MFC/C++ I
wrote a base class to take out all the thread-plumbing code, and
introduce heavy automisation. This feasible by making your own thread
class which expects to be derived from. True, maybe it is not the
best model, but it saves you a lot of code, and it is definitely a
lot more elegant. Honestly, I went one step further and all my
threads can do is execute tasks (also a base class which should
bederived from).

I think you could do all of that without deriving from the base class
though - you could pass the instance of your class a ThreadStart
delegate, and still get it to do all the work.
The point in making the abstraction is to automize and not having to
write code again and again. Plus the elegancy of code, and the ease
of reviewing.

Sure - but I haven't suggested duplicating code. I've just suggested
avoiding inheritence where it's unnecessary, as I believe it is in this
case. If you're not really changing the actual threading behaviour,
just giving it something different to run, using a ThreadStart delegate
to describe what should be run within a class which encapsulates the
rest of the threading behaviour you want.

To be honest, I haven't really *needed* to change the threading
behaviour beyond what a normal Thread.Start does - changing the name,
maybe, but that's about it. What does your class do?
Enfin, this is just my opinion but if I were to write threading code
in Java or any other language, it would probably be the first thing I
do: cover the messy threading details and use your pattern in _every_
language you can think of (if the languages/frameworks are
comparable). My threading code looks _very_ similar in all these
languages (C#, C++ ...) because the interface remains the same.

Doesn't that kinda go against your first sentence though? When some
languages provide facilities which make a design cleaner, why not use
it?
 
W

William Stacey [MVP]

True. If we did not have them, we could implement them with a monitor like
so:
http://www.mvptools.com/Doco/CSharp/Events.htm
Please post or write with errors or comments. Cheers!
--
William Stacey, MVP

TT (Tom Tempelaere) said:
Jon Skeet said:
Chris Mullins 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.
[...]
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.) [...]

If you are going to write an article on threading, events are a must
(ManualResetEvent and AutoResetEvent). There are situations in which these
more natural to use and more to the point. Plus if you don't use events, you
can't wait on multiple objects (unless you use Mutex directly instead of
Monitor or lock).
If I wouldn't have these event classes and the WaitHandle.WaitAny or
WaitHandle.WaitAll functions, I would have a lot of trouble implementing the
kernel I am now writing. Without the event classes it would at least be a
lot more complex to write (IMHO) and pbbl be less efficient (although you
can't just say that, one should test that).
 
W

William Stacey [MVP]

When I declare a locking object, I always make it readonly (or const if
static) to highlight the fact that the object it refers to will not >change.

Me too. There is at least two notable exceptions:
1) If your implementing IContainer, then you need to provide SyncRoot. If
you only have one lock, you may as well use "this" and save creating and
storing another object as effect would be the same.
2) If you have a collection (i.e. tree) that takes other objects (i.e.
nodes.) and they all lock on the same lock in Tree. In Node, you don't know
at construction what the lock will be, so you need to set it when added to
the Tree collection so can't use readonly.

Agree with rest. Cheers!
 
J

Jon Skeet [C# MVP]

William Stacey said:
static) to highlight the fact that the object it refers to will not >change.

Me too. There is at least two notable exceptions:
1) If your implementing IContainer, then you need to provide SyncRoot. If
you only have one lock, you may as well use "this" and save creating and
storing another object as effect would be the same.

Not unless you document it. People may be locking on your class
elsewhere.
2) If you have a collection (i.e. tree) that takes other objects (i.e.
nodes.) and they all lock on the same lock in Tree. In Node, you don't know
at construction what the lock will be, so you need to set it when added to
the Tree collection so can't use readonly.

Not sure I followed that, but I'm sure you're right :)
 
W

William Stacey [MVP]

Not unless you document it. People may be locking on your class
elsewhere.

..Net does not document this AFAICT, and they do this all the time for
collections. I they are locking on class, then they should lock on SyncRoot
instead as effect would be same. Maybe example of how this could bite you.

Cheers!
 
T

TT \(Tom Tempelaere\)

Jon Skeet said:
TT (Tom Tempelaere) <"=?Utf-8?B?VFQgKFRvbSBUZW1wZWxhZXJlKQ==?=" <_|\|_0
$P@|/\|titi____AThotmail.com|/\|@P$0_|\|_>> wrote:

[Deriving from thread or not]
What is true for Java isn't necessarily true for other languages.

True - but this is more of a general design issue rather than something
particularly language-specific.
But apart from that, a while ago when I needed threading in MFC/C++ I
wrote a base class to take out all the thread-plumbing code, and
introduce heavy automisation. This feasible by making your own thread
class which expects to be derived from. True, maybe it is not the
best model, but it saves you a lot of code, and it is definitely a
lot more elegant. Honestly, I went one step further and all my
threads can do is execute tasks (also a base class which should
bederived from).

I think you could do all of that without deriving from the base class
though - you could pass the instance of your class a ThreadStart
delegate, and still get it to do all the work.

That is just one aspect of threading. For instance you would like to be
notified of thread completion automatically (coded as an event in my
threading class). You would like an easy way to pass parameters to the
thread, just construct the class with the appropriate parameters. You would
like other console output for exceptions in threads (eg unhandled exception
handler, status output, debugging etcetc), write a launching handler with a
surrounding try-catch and output the way you want (this handler is also
necessary for firing the thread completion event), or handle any way you
want automatically. You would like a clean way to seperate thread execution
from thread cleanup for instance (automated of course), and have a clear
indication of how your thread should shutdown gracefully. This last one is
an overridable cancel method. The implemeter of the thread knows how your
thread can shut down gracefully so supplies implementation to do so. You
would like your thread behaviour to be encapsulated in a clean way. The
thread internals are protected (override) and private, and automated. The
public interface consists of threading functionality (start, abort, cancel,
joining, etc) and the things you want to be public (events ...).

Actually in my current threading lib I've gone one step further and added
the abstraction of seperating the thread and that what is executing on it.
That results in a task base class, and a thread class that can execute
tasks. I implemented task completion using WaitHandle (ManualResetEvent, set
when completed) so other threads/tasks can wait for them to finish. In my
current project I need to wait for several tasks to finish in one main
kernel thread, so I collect the task completion handles and wait for them
using WaitHandle.WaitAll. Easy writing.
Sure - but I haven't suggested duplicating code. I've just suggested
avoiding inheritence where it's unnecessary, as I believe it is in this

I completely agree. But in this case I think it is a good way to do so. I
have no objection against the fact that .NET made the Thread class sealed.
But my way of coding threads is elegant and automated. What do I need more?
case. If you're not really changing the actual threading behaviour,
just giving it something different to run, using a ThreadStart delegate
to describe what should be run within a class which encapsulates the
rest of the threading behaviour you want.

It all depends on what level you are programming I guess.
To be honest, I haven't really *needed* to change the threading
behaviour beyond what a normal Thread.Start does - changing the name,
maybe, but that's about it. What does your class do?

Not a _class_ but a _progam_. Basically a kernel for an industrial printer
which has to be multi-threaded because things need to execute in parallel
and be synchronized. No UI inside (of course), although a UI component can
plug in to monitor :).
Doesn't that kinda go against your first sentence though? When some
languages provide facilities which make a design cleaner, why not use
it?

I am using them, of course. Where did I say I didn't?

Actually I like my pattern but I don't see it reflected in any language. It
comes natural to me and obviously unnatural to others. Perhaps it is just a
matter of taste.

Cheers,
 
J

Jon Skeet [C# MVP]

William Stacey said:
.Net does not document this AFAICT, and they do this all the time for
collections.

That doesn't mean it's good practice, necessarily.
I they are locking on class, then they should lock on SyncRoot
instead as effect would be same.

Yes, they should lock on SyncRoot. However, I believe it's a bad idea
to present the opportunity for deadlock due to this for no particular
reason.
Maybe example of how this could bite you.

Normal deadlocking - one thread does:

lock (someCollection)
{
lock (somethingElse)
{
...
}
}

Another thread does:

lock (somethingElse)
{
lock (someCollection.SyncRoot)
{
...
}
}

Deadlock occurs if someCollection==someCollection.SyncRoot.
 
T

TT \(Tom Tempelaere\)

Jon Skeet said:
TT (Tom Tempelaere) <"=?Utf-8?B?VFQgKFRvbSBUZW1wZWxhZXJlKQ==?=" <_|\|_0


Now why didn't I think of that? Excellent idea.


But you don't know for sure whether something within Queue locks on
"this" itself. While that wouldn't be disastrous in this case, I think
it's a simpler policy to never lock on anything that isn't either
private to the class itself and used for nothing but locking, or
something which is explicitly exposed for locking purposes.

Sorry, but if you _own_ the queue then you _know_ where locks would be taken
on this from within the queue. In your case that is not an issue because
there is not a single method that causes a lock on this.
I think that's the right place to mention it though - if I talked about
memory barriers before talking about what they really are, it could get
very confusing. Maybe I could mention them with a link to the
volatility section...

I don't really agree with that. It is one of the known and desirable effects
of Monitor.Enter and Exit.
Mmm... the docs really aren't clear. I *suspect* they actually execute
a "real" volatile read/write as per the memory model, but it's hard to
say for sure. I'll mention them in an "unsure" kind of way...


Possibly. I personally think they should be avoided at almost all
costs, but I suppose mentioning that wouldn't be a bad idea :)

? Interrupt is a necessity if you wait or join ... I don't know what kind of
threads you write,but there are alot of waits in my program and I don't see
how I would stop them from waiting without an interrupt actually. Perhaps
you have an alternative? And what if the thread doesn't repond. It happens
you know. Then abort is about the best you can do. There is no avoiding
there the way I see it. Everything has its purpose in System.Threading. They
didn't put it in for the show.

And indeed it wouldn't be ;)

Cheers,
 
J

Jon Skeet [C# MVP]

TT (Tom Tempelaere) <"TT \(Tom Tempelaere\)" <_|\|_0§P@|/
\|titi____AThotmail.com|/\|@P§0_|\|_> said:
That is just one aspect of threading. For instance you would like to be
notified of thread completion automatically (coded as an event in my
threading class). You would like an easy way to pass parameters to the
thread, just construct the class with the appropriate parameters.

You can do that using delegates too.
You woul like other console output for exceptions in threads (eg unhandled exception
handler, status output, debugging etcetc), write a launching handler with a
surrounding try-catch and output the way you want (this handler is also
necessary for firing the thread completion event), or handle any way you
want automatically.

Again, you can do that with a delegate. There's nothing to say you have
to pass the delegate you're given straight to the Thread constructor.
You would like a clean way to seperate thread execution
from thread cleanup for instance (automated of course), and have a clear
indication of how your thread should shutdown gracefully.

Ditto. Supply one delegate for cleanup and one for execution, then
execute one followed by the other.
This last one is
an overridable cancel method. The implemeter of the thread knows how your
thread can shut down gracefully so supplies implementation to do so. You
would like your thread behaviour to be encapsulated in a clean way. The
thread internals are protected (override) and private, and automated. The
public interface consists of threading functionality (start, abort, cancel,
joining, etc) and the things you want to be public (events ...).

Again, that could be abstracted in a way that a delegate could use - it
could take the object to query for when it should be cancelled, etc.
Actually in my current threading lib I've gone one step further and added
the abstraction of seperating the thread and that what is executing on it..
That results in a task base class, and a thread class that can execute
tasks. I implemented task completion using WaitHandle (ManualResetEvent, set
when completed) so other threads/tasks can wait for them to finish. In my
current project I need to wait for several tasks to finish in one main
kernel thread, so I collect the task completion handles and wait for them
using WaitHandle.WaitAll. Easy writing.

Again, I see nothing to stop you from specifying the actual method to
execute using a ThreadStart delegate rather than using inheritance
though.
I completely agree. But in this case I think it is a good way to do so. I
have no objection against the fact that .NET made the Thread class sealed..
But my way of coding threads is elegant and automated. What do I need more?

Well, it prevents you from simply running a method in an existing class
which already derives from something else in a different thread (with
your added functionality), for a start. Using a delegate, you'd get all
the benefits of your base class etc but without needing to adjust the
natural class hierarchy just for the purpose of threading.

In my view, a delegate specifies exactly "something to run" - the whole
concept fits threading perfectly. Why not use it, rather than
inheritence?
It all depends on what level you are programming I guess.

Not sure what you mean by that.
Not a _class_ but a _progam_. Basically a kernel for an industrial printer
which has to be multi-threaded because things need to execute in parallel
and be synchronized. No UI inside (of course), although a UI component can
plug in to monitor :).

I was asking about your base class, but I think you've explained a lot
of it above anyway.
I am using them, of course. Where did I say I didn't?

Well, you said the interface remains the same. That means that if
you're using Java, you're not using C#'s events or delegates, for
instance. If you restrict your interface to the intersection of what
all the languages you're interested in support, you're bound to end up
with a less idiomatic interface.
Actually I like my pattern but I don't see it reflected in any language. It
comes natural to me and obviously unnatural to others. Perhaps it is justa
matter of taste.

Probably. I'm afraid I still don't like it.
 
J

Jon Skeet [C# MVP]

TT (Tom Tempelaere) <"TT \(Tom Tempelaere\)" <_|\|_0§P@|/
\|titi____AThotmail.com|/\|@P§0_|\|_> said:
Sorry, but if you _own_ the queue then you _know_ where locks would be taken
on this from within the queue. In your case that is not an issue because
there is not a single method that causes a lock on this.

I realise it's fine in this case, because we lock every time we're
going to do something with the queue anyway - but I prefer the simple
policy which doesn't need me to decide on a case-by-case basis whether
to lock on the object or on something which exists solely for locking
purposes. It's a matter of taste though.
I don't really agree with that. It is one of the known and desirable effects
of Monitor.Enter and Exit.

But it only makes sense if you understand memory barriers to start
with.
? Interrupt is a necessity if you wait or join ... I don't know what kindof
threads you write,but there are alot of waits in my program and I don't see
how I would stop them from waiting without an interrupt actually.

With a pulse, for a call to Wait. That's exactly what pulse is for. I
rarely use Thread.Join, but if I was considering the possibility of the
thread hanging, I'd probably use one of the versions that took a
timeout.
Perhaps you have an alternative? And what if the thread doesn't repond. It happens
you know. Then abort is about the best you can do.

Occasionally. A lot of the time I'd rather have a hung thread and abort
the whole process than abort a single thread and have it doing
potentially dangerous stuff.
There is no avoiding
there the way I see it. Everything has its purpose in System.Threading. They
didn't put it in for the show.

Well, I don't have to necessarily agree that everything should be used.
(Look at the Java API, where Thread.stop() is deprecated as being
basically unsafe.)

Besides, I've seen some evidence that an aborted thread in .NET can
have nasty effects, such as coming out of a Wait without regaining a
lock first. I don't want such a thread running around potentially
causing havoc with the rest of my well-threaded code.
 
T

TT \(Tom Tempelaere\)

TT (Tom Tempelaere) <"TT \(Tom Tempelaere\)" <_|\|_0§P@|/
\|titi____AThotmail.com|/\|@P§0_|\|_> said:
That is just one aspect of threading. For instance you would like to be
notified of thread completion automatically (coded as an event in my
threading class). You would like an easy way to pass parameters to the
thread, just construct the class with the appropriate parameters.

You can do that using delegates too.
You woul like other console output for exceptions in threads (eg unhandled exception
handler, status output, debugging etcetc), write a launching handler with a
surrounding try-catch and output the way you want (this handler is also
necessary for firing the thread completion event), or handle any way you
want automatically.

Again, you can do that with a delegate. There's nothing to say you have
to pass the delegate you're given straight to the Thread constructor.
You would like a clean way to seperate thread execution
from thread cleanup for instance (automated of course), and have a clear
indication of how your thread should shutdown gracefully.

Ditto. Supply one delegate for cleanup and one for execution, then
execute one followed by the other.
This last one is
an overridable cancel method. The implemeter of the thread knows how your
thread can shut down gracefully so supplies implementation to do so. You
would like your thread behaviour to be encapsulated in a clean way. The
thread internals are protected (override) and private, and automated. The
public interface consists of threading functionality (start, abort, cancel,
joining, etc) and the things you want to be public (events ...).

Again, that could be abstracted in a way that a delegate could use - it
could take the object to query for when it should be cancelled, etc.
Actually in my current threading lib I've gone one step further and added
the abstraction of seperating the thread and that what is executing on it.
That results in a task base class, and a thread class that can execute
tasks. I implemented task completion using WaitHandle (ManualResetEvent, set
when completed) so other threads/tasks can wait for them to finish. In my
current project I need to wait for several tasks to finish in one main
kernel thread, so I collect the task completion handles and wait for them
using WaitHandle.WaitAll. Easy writing.

Again, I see nothing to stop you from specifying the actual method to
execute using a ThreadStart delegate rather than using inheritance
though.
I completely agree. But in this case I think it is a good way to do so. I
have no objection against the fact that .NET made the Thread class sealed.
But my way of coding threads is elegant and automated. What do I need
more?

Well, it prevents you from simply running a method in an existing class
which already derives from something else in a different thread (with
your added functionality), for a start. Using a delegate, you'd get all
the benefits of your base class etc but without needing to adjust the
natural class hierarchy just for the purpose of threading.

In my view, a delegate specifies exactly "something to run" - the whole
concept fits threading perfectly. Why not use it, rather than
inheritence?
It all depends on what level you are programming I guess.

Not sure what you mean by that.
Not a _class_ but a _progam_. Basically a kernel for an industrial printer
which has to be multi-threaded because things need to execute in parallel
and be synchronized. No UI inside (of course), although a UI component can
plug in to monitor :).

I was asking about your base class, but I think you've explained a lot
of it above anyway.
I am using them, of course. Where did I say I didn't?

Well, you said the interface remains the same. That means that if
you're using Java, you're not using C#'s events or delegates, for
instance. If you restrict your interface to the intersection of what
all the languages you're interested in support, you're bound to end up
with a less idiomatic interface.
Actually I like my pattern but I don't see it reflected in any language. It
comes natural to me and obviously unnatural to others. Perhaps it is just a
matter of taste.

Probably. I'm afraid I still don't like it.

--
Jon Skeet - <[email protected]>


Jon, you can take this to an extreme, and just start coding C again.
Anything can be coded without classes and derivation or interface
inheritance (well, not really because .NET doesn't allow, but that's not the
point). Your call. I prefer OO if it suits and fits what I need to do. And
in this case I've proven for myself (at the very least) that this is the way
to go. But seems like this is not true for others, so in the end everyone
does things that suits him best. In all my threading apps I've been very
happy that I introduced these. There is no hard proof, just experience I
guess. I don't even know why Java threads made you fear thread-derivable
classes. I see only benefits in my approach, and no disadvantages up to this
point. I'm using the pattern for years now. So I'll stick to what I do for
several years with success now.

Your objections are rather thin. Anything can be done in another way; and I
think the alternative approach you suggest results in more code, and less
readable code because in each developer does things his way. The overridable
interface will remain the same for all thread-derivable classes, so no
differences in naming in each thread app because you can't just rename
overridables. A clear pattern that is the same in every app. That is what I
like to see in apps because they are easily reviewed. Everybody in the
company should stick to the pattern so that interchangeability of code
increases. I see every other guy coding threads in a different way and in
the company I work for for instance, I would like them to code threading all
in the same way. The same is true for other domains such as db access and
automisation, UI automisation, etc etc. Sure .NET has a nice library that
(nearly) does it all, but programmers styles differ too much, plus you see
programmers re-coding the same things over and over. I really hate this.

The fact that you have to derive from the base thread class is not bad,
because it should be the only thing it derives from. If you would want to
derive from more than one base class, then your design is obviously wrong. I
wouldn't even dare letting it implement an interface, because that is not
the intention when you derive from the thread. The thread encapsulates
everything that is on the thread, what is needed for the thread to start and
stop gracefully, what is run on the thread etc. It is the controller of what
executes on the thread, and that is a private matter (although the
overridables are protected - in C++ these can be private which is even
better for such patterns). And there is nothing else that such a thread
class should do. You will also want to seal the derived class directly
unless your design says otherwise. I seal by default unless my design says
otherwise.

I am not advocating the introduction of such a class in the .NET library.
The library fits my view of threads and how to make them maintainable. Each
threading app will use the same interface (the english word) of the library
and so all thread apps look the same. In my case they even look the same in
C++. Perfect. All thread main entry's have the same name and signature. All
thread canceling methods have the same name, the same signature. Thread
cleanup methods all have the same name. Ok, the event I used in C# is
different than what I did in C++, but the idea is completely the same
(callback) and is very elegant in both libraries. In my point of view there
is more to a thread than simply that was is run on it.

[]
Indeed, the interface hides the way threads are written in each language.
Sometimes the outer interface may differ because of different ways of doing
things, eg events (C#) vs listeneres (Java).

There are differences in the interfaces of course. Every language has things
that differ from others. Events in c#, listeners in Java and callbacks in
C/C++ (fptr). But the underlying idea remains the same. I'm not restricting
anything, I am assuring that the interface is consistent from a language
neutral point of view. Threading is similar in all languages from a high
level point of view, it's the internals that differ.

Anyway, I gotta go party at the city parade ;-) Ghent
(http://www.cityparade.be)

Cheers,
 

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