Multi-threading article finally "finished" - reviewers welcome

J

Jon Skeet [C# MVP]

Kiran said:
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.

this way the method that is run in the thread & the thread itself are
treated as from single object.

Whereas I would discourage that approach. It's the one that Java took
until it gained the Runnable interface, and these days most people will
strongly discourage people from subclassing Thread in Java.

I see no advantage in conflating the two ideas, to be honest. There's
nothing wrong with having a general purpose class which can be used to
start a thread and is still provided with a ThreadStart delegate to
actually run, but to restrict things by derivation is a bad idea, in my
view.
 
C

Cor Ligthert

Hi Jon,

I did not go deep in your page code, however what I see often in the
newsgroups that in my opinion people start using multithreading on the wrong
places.

To say it simple, I miss the chapter (or did not see it), "Why using
multithreading and when using multithreading".

The "why" is for me to use processor power when there is a process stopped
because that it needs user or another acknowledge on a process to let it go
on. Another process can than run in the time that waiting is done.

For the when it is for me.
-There has to be more processes, which are independent from a user, or any
other processes running, which can have interrupts because of IO or things
like that (and independent means even not need an end acknowledge going on).
-When this is not the issue however there are more processors and known that
there is only one application running there can be used optimistic
multithreading.

A nice example is printing which is by default because it is done by the OS
already a multithreading process. (For you because you are in my opinion so
on words, that is multiprocessing (or even a better classic word for it
multiprogram) in fact, however when it not has been, it would have been nice
to do it multithreading).

This is only to give you some ideas about this.

Cor
 
J

Jon Skeet [C# MVP]

Cor Ligthert said:
I did not go deep in your page code, however what I see often in the
newsgroups that in my opinion people start using multithreading on the wrong
places.

To say it simple, I miss the chapter (or did not see it), "Why using
multithreading and when using multithreading".

Yes, that wouldn't be a bad idea.
The "why" is for me to use processor power when there is a process stopped
because that it needs user or another acknowledge on a process to let it go
on. Another process can than run in the time that waiting is done.

Not necessarily. It also allows things like a UI updating while doing
something else in the background as well.
For the when it is for me.
-There has to be more processes, which are independent from a user, or any
other processes running, which can have interrupts because of IO or things
like that (and independent means even not need an end acknowledge going on).

They don't need to be indepedent, or use interrupts. It's quite
possible to have a CPU-bound background thread (preferably at a low
priority), and have it update the UI (using Control.Invoke) to give the
end user information about what's happening.
-When this is not the issue however there are more processors and known that
there is only one application running there can be used optimistic
multithreading.

Not sure what you mean here. Could you try rewriting that sentence?
A nice example is printing which is by default because it is done by the OS
already a multithreading process. (For you because you are in my opinion so
on words, that is multiprocessing (or even a better classic word for it
multiprogram) in fact, however when it not has been, it would have been nice
to do it multithreading).

(The disadvantage with doing it in threads rather than using a separate
spooler is that you'd have to keep the application running while you
were printing, of course.)

I already draw a bit of a parallel between multi-tasking and multi-
threading, but I agree that it would be a good idea to write more about
it, with other examples.
 
C

Cor Ligthert

Hi Jon,

And again starts a discussion.
Not necessarily. It also allows things like a UI updating while doing
something else in the background as well.
This gives no advantages only slower UI updating. There is no advantage when
other processors do not take things over, only slower UI, however when other
processors are taking things over (what can be in painting), than it is
again IO and you can do it in more threads.

As far as I know does, although the hyper threading optimizes the
multithreading process, a processor only one thing in a time.
They don't need to be indepedent, or use interrupts. It's quite
possible to have a CPU-bound background thread (preferably at a low
priority), and have it update the UI (using Control.Invoke) to give the
end user information about what's happening.
This is in my opinion only interesting when there is an actif foreground
thread, than it completly as I tried to write.

More processorrs:
What I wrote above is not always true when there are more processors,
however this is not really a multithreading isue.

When there is only one application running, you can use the not used
processors to do processing in an optimistic way. When there is a reason it
can not be used you can garbage it. However do never forget that 2
processors have to be processed.

I hope this gives some more explanations about my thoughts about this?

Cor
 
J

Jon Skeet [C# MVP]

Cor Ligthert said:
And again starts a discussion.
This gives no advantages only slower UI updating.

Yes it does!

1) You can give the user information as to progress
2) If windows are dragged over the UI, it can repaint rather just
leaving a white rectangle
3) You can allow buttons etc for cancelling the other thread's work,
and the app can be closed in the normal way
4) The user may be able to do other things while the processing is
going on (depending on the app)
There is no advantage when
other processors do not take things over, only slower UI, however when other
processors are taking things over (what can be in painting), than it is
again IO and you can do it in more threads.

The point is that you have a *working* UI. It will be slower than if
there isn't the other process, but it's better than a completely
unresponsive UI.
As far as I know does, although the hyper threading optimizes the
multithreading process, a processor only one thing in a time.

No - hyperthreading makes the processor look like two processors as far
as the OS is concerned, so two threads can run on it at the same time,
using different parts of the processor.
This is in my opinion only interesting when there is an actif foreground
thread, than it completly as I tried to write.

The UI *is* an active foreground thread. If you want the UI to remain
responsive *at all* then either you need to call Application.DoEvents
(urgh!) or you need another thread.
More processorrs:
What I wrote above is not always true when there are more processors,
however this is not really a multithreading isue.

Well, it's something you need to be aware of when threading - you may
wish to tailor the number of threads you use depending on the number of
processors, in some special cases. (I could mention that in the
article, actually.)
When there is only one application running, you can use the not used
processors to do processing in an optimistic way. When there is a reason it
can not be used you can garbage it. However do never forget that 2
processors have to be processed.

I hope this gives some more explanations about my thoughts about this?

Yes, but I disagree very strongly. It would be easy to come up with a
couple of example programs, one of which uses threading and one of
which doesn't, if you're still not convinced.
 
C

Cor Ligthert

Jon,

Please no constructive quoting otherwise we can better stop this, I am sure
you do it not express, however read first the complete message and add than
your comments?
Yes it does!

1) You can give the user information as to progress
2) If windows are dragged over the UI, it can repaint rather just
leaving a white rectangle
3) You can allow buttons etc for cancelling the other thread's work,
and the app can be closed in the normal way
4) The user may be able to do other things while the processing is
going on (depending on the app)

I wrote 4. The others can be done in another way while there is than a
higher throughput, I get very much the idea that you forget that the OS has
to process the threads, which is not measurable inside a program.
The point is that you have a *working* UI. It will be slower than if
there isn't the other process, but it's better than a completely
unresponsive UI.
See my previous sentence.
No - hyperthreading makes the processor look like two processors as far
as the OS is concerned, so two threads can run on it at the same time,
using different parts of the processor.

You write, "No", what is the difference with what I wrote? You write "run"
which is true, I wrote "process" in my opinion are that two different
things.
The UI *is* an active foreground thread. If you want the UI to remain
responsive *at all* then either you need to call Application.DoEvents
(urgh!) or you need another thread.

see my previous sentence
Well, it's something you need to be aware of when threading - you may
wish to tailor the number of threads you use depending on the number of
processors, in some special cases. (I could mention that in the
article, actually.)


Yes, but I disagree very strongly. It would be easy to come up with a
couple of example programs, one of which uses threading and one of
which doesn't, if you're still not convinced.
I do use multithreading and there are a lot of advantages, however I have
seen that it is used in some circumstances not needed. Processing
multithreading takes time, so it can have a negative influence on the
througput of the program.


Cor
 
J

Jon Skeet [C# MVP]

Cor Ligthert said:
Please no constructive quoting otherwise we can better stop this, I am sure
you do it not express, however read first the complete message and add than
your comments?

I really don't know what you mean. I haven't done any creative snipping
or anything here...
I wrote 4.

Where, exactly? Maybe it was in one of the sentences where I didn't
fully understand your meaning.
The others can be done in another way while there is than a
higher throughput, I get very much the idea that you forget that the OS has
to process the threads, which is not measurable inside a program.

No, the others are *definitely* better done using threads. How else
would you do it? Using Application.DoEvents()? That leads to horrible
re-entrancy problems, in my opinion, and is really a hack dating back
to a time when threads weren't easily available. It also involves
guesswork as to where is a good place to call DoEvents - the more often
you call it, the more throughput you lose, but the less often you call
it, the less responsive the UI is.
See my previous sentence.

You've never said how you'd achieve a working GUI, as far as I've seen.
You write, "No", what is the difference with what I wrote? You write "run"
which is true, I wrote "process" in my opinion are that two different
things.

You didn't actually write any verb in that clause - you just wrote "a
processor only one thing at a time". However, a hyperthreading
processor really *can* be processing two threads at a time. For
instance, an instruction for one thread might be being decoded while
the instruction for another thread runs in the floating point unit.
Given the deep pipelining in many processors, this is only a more
complicated version of what's been happening for ages, with many
instructions being processed at the same time anyway. It's just that in
the past, those instructions all had to be from the same thread.
see my previous sentence

I really don't see how that covers it. Or are you advocating UIs which
are unresponsive? Note that "unresponsive" doesn't just mean that the
user needs to be able to do other things - an app which doesn't even
repaint is unresponsive, in my view.

I do use multithreading and there are a lot of advantages, however I have
seen that it is used in some circumstances not needed. Processing
multithreading takes time, so it can have a negative influence on the
througput of the program.

It certainly can - but not in the examples presented here. Or rather,
the throughput *will* be very slightly diminished, but at the gain of a
*much* better user experience. I would rather have an interface which
took 4 hours to do something but kept me informed of what was going on,
let me cancel it, etc than an app which took 3 hours and 55 minutes but
never bothered to repaint itself.
 
C

Cor Ligthert

Hi Jon,

I stop with this thread, I wrote you why I did it and was not interested
starting a discussion about this.

The differences are so thin, that it makes no sense the only thing I would
bring to you is that a thread is not forever the solution as I often get the
idea that some people are thinking, it can be a sollution and you have to
think twice before you use it.

I gave you some samples to help you to add to your page, when you do not
agree that with me is for me no problem, do it your way, it are your pages.

Do not think I am angry or something, I am not at all.

However this are parts where in my opinion I can be right and where you can
be right depending on the circumstances, so discussing using a newsgroup
makes it to difficult.

Cor
 
J

Jon Skeet [C# MVP]

However this are parts where in my opinion I can be right and where you can
be right depending on the circumstances, so discussing using a newsgroup
makes it to difficult.

If you say so. I don't think it's *ever* right (in anything but a
throwaway test program) to perform long-running operations in the UI
thread, unless they absolutely *have* to due to them making a lot of
changes to the UI controls themselves. Almost anything not directly
related to the UI shouldn't occur on the UI thread, in my view. I think
you'll find most people would agree with me on that, too.

I'll certainly add something to the page about some times when it's
*not* worth creating lots of threads, or when you create a thread but
then don't use the fact that you've created it (e.g. by calling
BeginInvoke and then calling EndInvoke on the next line, which
effectively makes it synchronous anyway).
 
T

Ted Miller

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#...

See Thread.VolatileRead and Thread.VolatileWrite.
 
T

Ted Miller

This is not surprising at all. The distinction between Monitor and Mutex in
..Net is the same as the distinction between critical sections and mutexes in
Win32. The critical section will in many cases completely bypass the
underlying lock. If you have multiple processors, you increase concurrency
and therefore lock contention, forcing the crit sect to actually enter its
underlying lock more often.
 
T

Ted Miller

You might consider including some discussion of ReaderWriterLock -- kind of
an advanced feature, but could be useful in certain scenarios.
 
W

William Stacey [MVP]

This is not surprising at all. The distinction between Monitor and Mutex
in
.Net is the same as the distinction between critical sections and mutexes in
Win32. The critical section will in many cases completely bypass the
underlying lock. If you have multiple processors, you increase concurrency
and therefore lock contention, forcing the crit sect to actually enter its
underlying lock more often.

FWIW, here is a simple critical section in c#. A lot more state could be
added, but this is basic.

using System;
using System.Threading;

namespace SyncPrimitives
{
/// <summary>
/// Simple CriticalSection Implementation in c#.
/// Note we don't use a "busy wait" but a test and sleep method.
/// The current thread gives up it cpu slice to allow another thread to
run.
/// The idea is that owner thread will run and release the lock and we will
get
/// the lock when we wake and test again. This should be the normal
behavior
/// if critical sections are only used to protect very short sections
/// of code. Two threads will only rarely attempt to enter the critical
section
/// at the same time, and even then, the loser will only have to spin/sleep
for
/// a brief time. We could also upgrade to waiting on an event, but that
would be
/// another version and we only want to show simple implementation. We
could
/// also add thead "state" so that only owner can Exit and owner can
reenter lock.
/// </summary>
public sealed class CriticalSection
{
private int spinLock = 0; // Not locked.
public CriticalSection()
{
}
/// <summary>
/// Enter the CriticalSection exclusively or wait until we do.
/// A CriticalSection is intended to be Entered and Exited quickly.
/// </summary>
public void Enter()
{
while( Interlocked.Exchange(ref spinLock, 1) == 1 )
Thread.Sleep(0);
// We got the lock as it was 0 (unlocked) before Exchange.
}
public bool Enter(int milliseconds)
{
if ( Interlocked.Exchange(ref spinLock, 1) == 0 )
return true;
Thread.Sleep(milliseconds);
if ( Interlocked.Exchange(ref spinLock, 1) == 0 )
return true;
return false;
}
/// <summary>
/// Non-blocking version of Enter method.
/// </summary>
/// <returns></returns>
public bool TryEnter()
{
if ( Interlocked.Exchange(ref spinLock, 1) == 0 )
return true;
return false;
}
/// <summary>
/// Release the lock. Note that any thread could call Exit with this
/// implementation, which resembles Semaphore Release behavior.
/// </summary>
public void Exit()
{
Interlocked.Exchange(ref spinLock, 0);
}
public bool IsLocked()
{
if ( Interlocked.CompareExchange(ref spinLock, 0, 0) == 0 )
return false;
return true;
}
}
}
 
J

Jon Skeet [C# MVP]

Ted Miller said:
You might consider including some discussion of ReaderWriterLock -- kind of
an advanced feature, but could be useful in certain scenarios.

Yup, it's on my wishlist.
 
V

Valery Pryamikov

Hi,
Spinlock could be fine if it is held only occasionally (i.e. once in a
while) and only for a few loops. Otherwise it is quite bad for laptop
battery power. Nowadays processor architectures/technologies such as Intel's
SpeedStep/Clock Modulation, AMD's PowerNow and Transmeta Crusoe Longrun
support dropping of processor's clock frequency based on processor's usage
pattern. Ie. if processor finds that it uses lots of time in idle, then it
is free to drop frequency for saving battery power (both less power
consumption by processor itself and better thermal control - i.e. less power
to fans). Spinlock is actually an attempt to simulate thread's idle wait but
from processor point of view it is indistinguishable from any other
processing intensive operations (definitely not an idle). Every spinlock
resets processor's last contiguous idle time slice and reduces overall
weight of idle time. Frequent use of spinlocks could cause that processor
will be always running on high frequency without any reasons, burning
battery power just for running dumb spins and fans that has to work double
for cooling overloaded processor. If someone sits on the plain with the
laptop and run program that relies on spinlocks - he/she would not really
appreciate what this program does for his/her batteries (not speaking of
extreme circumstances when people burns genitalia by their laptops see:
http://www.wired.com/news/business/0,1367,56552,00.html).


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

Cor Ligthert

Hi Jon,

Not about the rest of this thread, only about your answer and not agreeing
with you all the rest you stated, however to give you "one" sample to think
about.
Almost anything not directly
related to the UI shouldn't occur on the UI thread, in my view. I think
you'll find most people would agree with me on that, too.

Every process shorter than the human reaction time of the client is useless
to place in an extra thread.

Cor
 
J

Jon Skeet [C# MVP]

Cor Ligthert said:
Not about the rest of this thread, only about your answer and not agreeing
with you all the rest you stated, however to give you "one" sample to think
about.

Every process shorter than the human reaction time of the client is useless
to place in an extra thread.

Yes, I'd agree with you on that one, if you can really guarantee it'll
take that short a time.
 
W

William Stacey [MVP]

Spinlock could be fine if it is held only occasionally (i.e. once in a
while) and only for a few loops.

Correct. I think I pointed that out in the code.
to fans). Spinlock is actually an attempt to simulate thread's idle wait but
from processor point of view it is indistinguishable from any other
processing intensive operations (definitely not an idle). Every spinlock

Note this is not a busy-wait. The spin sleeps or gives up it slice so the
owner can free it. If the owner is busy, the cpu is working anyway. If the
owner is done, the next thread gets the lock, does its thing, and exits the
lock. This issue can arise if the owner blocks for long time while owning
the lock. That is not good and another lock should be used. It should only
be protecting a few lines in most cases. AFIK, every primitive is
ultimately based on a spin lock at the lowest level. So spins are mostly
used for creating higher sync primitives. If this is not the case, please
inform.
If someone sits on the plain with the
laptop and run program that relies on spinlocks - he/she would not really
appreciate what this program does for his/her batteries (not speaking of
extreme circumstances when people burns genitalia by their laptops see:
http://www.wired.com/news/business/0,1367,56552,00.html).

Actually that kinda happened to me once, so I feel the pain :) Cheers.
 
W

William Stacey [MVP]

Here is another version I did that goes right to an event wait if lock is
locked. Please review for errors and comments as this is a bit tricky. You
could cheat and use a Monitor, but that would not be very interesting.
Cheers!

using System;
using System.Threading;

namespace SyncPrimitives
{
/// <summary>
/// Simple CriticalSection Implementation in c#.
/// Note we don't use a "busy wait" but a test and wait.
/// This version uses event wait if lock is owned and keeps state of
current owner.
/// </summary>
public sealed class CriticalSection
{
private volatile Thread owner = null;
private int lockCount = 0;
private readonly AutoResetEvent lockedEvent = new AutoResetEvent(false);
private const int maxSpinCount = 400;

public CriticalSection()
{
}

public bool Enter(int milliseconds)
{
DateTime startTime;
int spinCount = 0;
//Block while locked (unless we are the owner).
while( Interlocked.CompareExchange(ref lockCount, 1, 0) > 0 )
{
// It is locked, so check if we are the owner.
if ( Object.ReferenceEquals(owner, Thread.CurrentThread) )
{
// We already own the lock, so just increment count.
lockCount++;
return true;
}

// Note if we get to this point, we are not the owner.
if ( milliseconds == 0 )
return false;

if ( spinCount < maxSpinCount )
{
spinCount++;
Thread.Sleep(0); // Don't WaitOne() until we have tried
maxSpinCount Times.
continue; // The idea is we will get the lock very
quickly and don't want overhead of wait in the fast path.
}

startTime = DateTime.Now;
try
{
if ( ! lockedEvent.WaitOne(milliseconds, false) )
return false; // Did not get a signal within timeout.
}
catch
{
lockedEvent.Set(); // Could be got signalled before the exception, so
signal next thread.
throw;
}
milliseconds = (int)(milliseconds - ((TimeSpan)(DateTime.Now -
startTime)).TotalMilliseconds);
if ( milliseconds < 0 )
milliseconds = 0;
}
// We got the lock and set to 1 as prev lockCount was zero.
owner = Thread.CurrentThread;
return true;
}

public bool TryEnter()
{
return Enter(0);
}

public void Exit()
{
if ( Interlocked.CompareExchange(ref lockCount, 0, 0) == 0 )
throw new SynchronizationLockException("Can not exit lock that has not
been entered.");

// It is locked. See if we are the owner. If not, throw exception.
if ( ! Object.ReferenceEquals(owner, Thread.CurrentThread) )
throw new SynchronizationLockException("Not current owner of lock.");

// We are the owner, so decrement count.
lockCount--;
if ( lockCount == 0 )
{
owner = null;
lockedEvent.Set();
}
}

public bool IsLocked()
{
if ( Interlocked.CompareExchange(ref lockCount, 0, 0) == 0 )
return false;
return true;
}
}
}
 
S

Scott Allen

Interesting point Valery.

It's hard to write spinlock at the level of abstraction we are at in
..NET. Ideally the JIT compiler could choose a spinlock implementation
based on the environment. On a single processor machine the spinning
is a waste of processor time, and on a laptop the spinlock causes
additional power consumption - both good reasons to switch to a
different implementation in these environments.
 

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