f



To thread or not to thread ?

The threads of discussion about threads have been enlightening in exposing
some of the low level issues which could possibly affect MT code and,
more importantly, served also to bring awareness to the unsuspecting (me
for one). It leaves me wondering if writing MT code is even to be pursued
at this point in time, or at least "where's the guidebook to read is that
will
facilitate the writing of MT code without engaging compiler-level
gotchas?". Can the low level issues be dealt with in the short term by
following certain rules, perhaps platform-specific ones, or is robust MT
code not a possibility at all at this time? Are the low level issues just
ones
of portability and therefor all those MT Windows programs developed
over the last few years, for example, can be considered probably OK in
regards to those compiler-level issues?

John



--
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
JohnQ
1/9/2007 7:56:03 AM
comp.lang.c++.moderated 10738 articles. 1 followers. allnor (8510) is leader. Post Follow

96 Replies
1124 Views

Similar Articles

[PageSpeed] 23

JohnQ wrote:
> The threads of discussion about threads have been enlightening in exposing
> some of the low level issues which could possibly affect MT code and,
> more importantly, served also to bring awareness to the unsuspecting (me
> for one). It leaves me wondering if writing MT code is even to be pursued
> at this point in time, or at least "where's the guidebook to read is that
> will
> facilitate the writing of MT code without engaging compiler-level
> gotchas?". Can the low level issues be dealt with in the short term by
> following certain rules, perhaps platform-specific ones, or is robust MT
> code not a possibility at all at this time? Are the low level issues just
> ones
> of portability and therefor all those MT Windows programs developed
> over the last few years, for example, can be considered probably OK in
> regards to those compiler-level issues?

IMO, you can write robust multi-threading applications today that work
on the major operating systems (Windows, Unix, etc.)  And yes, the
issues are primarily related to finding a common API that more or less
remains constant and making sure that the OS designer has provided a
sufficient set of kernel-mode primitives.

With my own projects, I decided to familiarize myself with the
synchronization primitives on one platform (Windows), knowing that, if
the engineers "thought it through" enough, then most likely, there will
be parallel primitives on the other platforms.  Many of the people who
did the Windows kernel-mode work came from VMS (I heard), which
probably explains why I have been so pleasantly surprised that they did
"think it through" in times of doubt. (PulseEvent notwithstanding).
IBM wrote a series of articles for porting multi-threaded applications
that will help get a broad overview of who is doing what. Things like
named kernel-mode primitives can be highly useful, and have been with
Windows for a long time, but not so long on Linux.  What would help is
help is to have a comprehensive set of kernel-mode primitives across
all OSes, but of course, this can force the question of what is
fundamental and what is not, for example, with whether there should be
real, bona-fide, intra-process threads. [Yes on Windows, Not Always on
Unix].

http://www-128.ibm.com/developerworks/library/l-ipc2lin2.html

I wrote a C++ wrapper framework that encapsulates the OS primitives on
Windows.  Naturally, this implies that one has thought about usage
patterns of synchronization in multi-threaded applications, which,
while not too difficult for the easier primitives like events, mutexes,
and semaphores,...becomes a bit harder when you try to make a "thread
class".  Many programmers have tried to make "thread classes" only to
find that there is a severe penalty for choosing a wrong conceptual
model.  I fell into this trap.  The best advice I can give in this
regard is to say that the concept of the thread itself should not be
modeled as a class.

The other best advice I can give, by far, is not to underestimate
WaitForMultipleObjects on Windows and its equivalents on other OSes.
It provides significant mental relief while design systems where many
different things are happening at once and all need to be waited on by
multiple threads, and yet still, you want to have the confidence that
the design is will scale no matter how many global objects you have an
no matter how many threads you have running (within reason).  For
example, 25 global  objects with, say, 20 distinct threads, each thread
operating on 3 or 4 of the global objects, would be easy conceptually
with WaitForMultipleObjects, but could quickly turn into a quagmire if
trying to accomplish the same thing with WaitForSingleObject and
time-outs.

-Le Chaud Lapin-


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Le
1/10/2007 12:18:52 PM
"Le Chaud Lapin" <jaibuduvin@gmail.com> wrote in message
news:1168399666.909953.168890@p59g2000hsd.googlegroups.com...
> JohnQ wrote:
>> The threads of discussion about threads have been enlightening in 
>> exposing
>> some of the low level issues which could possibly affect MT code and,
>> more importantly, served also to bring awareness to the unsuspecting (me
>> for one). It leaves me wondering if writing MT code is even to be pursued
>> at this point in time, or at least "where's the guidebook to read is that
>> will
>> facilitate the writing of MT code without engaging compiler-level
>> gotchas?". Can the low level issues be dealt with in the short term by
>> following certain rules, perhaps platform-specific ones, or is robust MT
>> code not a possibility at all at this time? Are the low level issues just
>> ones
>> of portability and therefor all those MT Windows programs developed
>> over the last few years, for example, can be considered probably OK in
>> regards to those compiler-level issues?
>
> IMO, you can write robust multi-threading applications today that work
> on the major operating systems (Windows, Unix, etc.)

Well obviously anyone who's been reading the thread threads knows that
is what you think!

>  And yes, the
> issues are primarily related to finding a common API that more or less
> remains constant and making sure that the OS designer has provided a
> sufficient set of kernel-mode primitives.

Doesn't ACE attempt to provide a wrapper across current platforms?
That sounds wrought with peril given the discussions here lately.
Probably better to be platform-specific at this juncture.

It be nice for the compiler guys at Microsoft to chime in and say that
they've thought about issues brought up here and get them to say
absolutely say yes or no as to whether there are potential dangers and
what they are. I know that after following the thread threads I'm not going
to be turning on the optimization flags on the compiler anytime soon for
one thing.

> With my own projects, I decided to familiarize myself with the
> synchronization primitives on one platform (Windows), knowing that, if
> the engineers "thought it through" enough, then most likely, there will
> be parallel primitives on the other platforms.  Many of the people who
> did the Windows kernel-mode work came from VMS (I heard),

And with VMS being a realtime OS, that bodes well.

> which
> probably explains why I have been so pleasantly surprised that they did
> "think it through" in times of doubt. (PulseEvent notwithstanding).
> IBM wrote a series of articles for porting multi-threaded applications
> that will help get a broad overview of who is doing what. Things like
> named kernel-mode primitives can be highly useful, and have been with
> Windows for a long time, but not so long on Linux.  What would help is
> help is to have a comprehensive set of kernel-mode primitives across
> all OSes, but of course, this can force the question of what is
> fundamental and what is not, for example, with whether there should be
> real, bona-fide, intra-process threads. [Yes on Windows, Not Always on
> Unix].

Well get the UNIX folks to pick up on the Windowisms is not going to
happen (though I personally wish it would because that's where I'm
from).

> http://www-128.ibm.com/developerworks/library/l-ipc2lin2.html
>
> I wrote a C++ wrapper framework that encapsulates the OS primitives on
> Windows.  Naturally, this implies that one has thought about usage
> patterns of synchronization in multi-threaded applications, which,
> while not too difficult for the easier primitives like events, mutexes,
> and semaphores,...becomes a bit harder when you try to make a "thread
> class".  Many programmers have tried to make "thread classes" only to
> find that there is a severe penalty for choosing a wrong conceptual
> model.

What kind of penalty? Performance or constrained design possibilities?

> I fell into this trap.  The best advice I can give in this
> regard is to say that the concept of the thread itself should not be
> modeled as a class.

That's exactly how I did it years ago. That's probably where I'd start
from again if/when I dust off and revive that code. I was probably
influenced by the Borland class library and maybe even MFC. So
you think they got it wrong huh?

> The other best advice I can give, by far, is not to underestimate
> WaitForMultipleObjects on Windows and its equivalents on other OSes.

Why would anyone "underestimate" that? My guess is you're talking
about those who have a UNIX/POSIX background right?

> It provides significant mental relief while design systems where many
> different things are happening at once and all need to be waited on by
> multiple threads, and yet still, you want to have the confidence that
> the design is will scale no matter how many global objects you have an
> no matter how many threads you have running (within reason).  For
> example, 25 global  objects with, say, 20 distinct threads, each thread
> operating on 3 or 4 of the global objects, would be easy conceptually
> with WaitForMultipleObjects, but could quickly turn into a quagmire if
> trying to accomplish the same thing with WaitForSingleObject and
> time-outs.

Why have more threads than the number of processor cores?

John


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
JohnQ
1/10/2007 4:05:13 PM
JohnQ wrote:

> Why have more threads than the number of processor cores?

I'm baffled by this question ...

The above question is exactly equivalent to "why would we want
multithreading?"

If you have several things to do in the morning (like, right
after waking up and going to work), such as making coffee;
a process in which you turn on a switch, and your machine
does everything else --- albeit, taking three minutes before
it's finished;  then, you just have to grab a cup/mug and pour
the coffee and drink it, turn on the TV to see the weather
forecast (or firing up your PC and connect to whatever dot
com you use for the weather), and then iron your shirt... Just
because you have a single body (single brain, single pair of
hands, etc.), would you force yourself to do those tasks
sequentially??  Would you refuse to go check the weather during
the three minutes that the coffee machine is taking to finish
your coffee?

For the longest time, people have done *multi*threading with
single CPU platforms.  The above is a simple analogy for the
reasons why people have gone for multithreading  (extremely
simplified, in that it doesn't cover all the reasons, or the
reasons why it would have to be multithreading and not other
approaches).

If you're talking about CPU-bound tasks, then yes, multithreading
doesn't make sense (for single-CPU machines), and with multi-
core CPUs or SMP, it wouldn't make sense to have more threads
than CPUs (or CPU cores)...  But from there to your question
above, that's a bit of a stretch, don't you think?

Carlos
--

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Carlos
1/10/2007 8:16:03 PM
Carlos Moreno wrote:
> JohnQ wrote:
> 
>> Why have more threads than the number of processor cores?
> 
> I'm baffled by this question ...
> 
> The above question is exactly equivalent to "why would we want
> multithreading?"
> 

Not quite. There are two different perspectives on multi-threaded 
programming. On is "distribute the workload optimally among the 
available processors." That's when you want just as many threads as 
processor cores. The other is "logically divide the process into tasks 
that can be run concurrently." That's when you want as many threads as 
appropriate, and are willing to put up with some thrashing and delays 
when you have more threads than cores.

-- 

	-- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and 
Reference." (www.petebecker.com/tr1book)

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Pete
1/11/2007 2:39:58 AM
JohnQ wrote:

> Doesn't ACE attempt to provide a wrapper across current platforms?

There is also boost.thread, which is very similar to what will be 
provided by the C++ standard.

It follows the POSIX C model.


> That sounds wrought with peril given the discussions here lately.
> Probably better to be platform-specific at this juncture.

For today, just depend on POSIX.
However, POSIX doesn't define everything for C++, since it is for C.

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Mathias
1/11/2007 2:55:44 AM
JohnQ wrote:
> "Le Chaud Lapin" <jaibuduvin@gmail.com> wrote in message
> news:1168399666.909953.168890@p59g2000hsd.googlegroups.com...
> > JohnQ wrote:
> Doesn't ACE attempt to provide a wrapper across current platforms?
> That sounds wrought with peril given the discussions here lately.
> Probably better to be platform-specific at this juncture.

Not sure.  Incidentally, there s a strong parallel between the type of
work I do and parts of ACE.  I will take a look.

[snippage]

> Well get the UNIX folks to pick up on the Windowisms is not going to
> happen (though I personally wish it would because that's where I'm
> from).

I had more experience with Windows than Unix for a long time until
length of time with Windows overtook length of time with Unix.  I never
thought I would say it, but the thought of not having bona-fide threads
is frightening.  I wonder if there will ever be convergence on things
like this (file system being another example).  Or asked another way,
"Are there fundamental themes that are universal, like the notion of a
stack?"

> > I wrote a C++ wrapper framework that encapsulates the OS primitives on
> > Windows.  Naturally, this implies that one has thought about usage
> > patterns of synchronization in multi-threaded applications, which,
> > while not too difficult for the easier primitives like events, mutexes,
> > and semaphores,...becomes a bit harder when you try to make a "thread
> > class".  Many programmers have tried to make "thread classes" only to
> > find that there is a severe penalty for choosing a wrong conceptual
> > model.
>
> What kind of penalty? Performance or constrained design possibilities?

Design possibilities and structural sensibility.  I forget the
thought-process I went through while making my thread frame work, but I
did go deep into the rat hole.  When I came out, I concluded that you
should use explicit new() and delete() to make thread "objects".  Mirek
Fidler apparently has an alternative model that uses full-blown RAII.


> That's exactly how I did it years ago. That's probably where I'd start
> from again if/when I dust off and revive that code. I was probably
> influenced by the Borland class library and maybe even MFC. So
> you think they got it wrong huh?

It seemed so.  Of course, I did not just make a thread class.  I tried
to think about it from a systemic point of view.  For example, thread
cancellation with orderly shutdown of that thread is desirable.  I
might be nice to wait for a thread to die.  It might be nice to wait
for an event, three mutexes, a semaphore, and 2 threads to die, or any
one of these things to be signaled, etc.    I was able to make all
classes RAII, Yin/Yang style (mutexes, etc) except the thread class.

> > The other best advice I can give, by far, is not to underestimate
> > WaitForMultipleObjects on Windows and its equivalents on other OSes.
>
> Why would anyone "underestimate" that? My guess is you're talking
> about those who have a UNIX/POSIX background right?

Or even Windows.  I went for a long while just using
WaitForSingleObject, with an occasional timeout.  But there are moments
when you are designing a system that, even thought it works, it simply
does not feel quite right.  In this case, I heard myself saying, "Ok,
this works, but it's ugly.  Too bad there is no way to wait for many
things at same time...that is..." Then I remembered
WaitForMultipleObjects.  I wrapped it and integrated it into the
framework.  I used my Event, Mutex, Semaphore, List<> and Set<> classes
to work with it..and in one afternoon, got rid of all the timeout
values that I had been using for WaitForMultipleObjects.  One function
shrunk in size from 800 lines to 300.  And the code made sense.  Of
course, Microsoft's limitation of handles let you only wait for 32, but
so far, I wait on maybe 7 or 8 objects at once.  And it is all in C++.
As you can guess, I am really excited about this.  Finally, blocking
can really be blocking, indefinitely, instead of say, for 8 hours then
checking to see if you are hung.

> > It provides significant mental relief while design systems where many
> > different things are happening at once and all need to be waited on by
> > multiple threads, and yet still, you want to have the confidence that
> > the design is will scale no matter how many global objects you have an
> > no matter how many threads you have running (within reason).  For
> > example, 25 global  objects with, say, 20 distinct threads, each thread
> > operating on 3 or 4 of the global objects, would be easy conceptually
> > with WaitForMultipleObjects, but could quickly turn into a quagmire if
> > trying to accomplish the same thing with WaitForSingleObject and
> > time-outs.
>
> Why have more threads than the number of processor cores?

The threads are not simply replicas of thread T, they are T, U, V, W,
and Z, all different.  At any given time most, if not all, are in
wait-state, consuming essentially no quanta.

-Le Chaud Lapin-


--
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Le
1/11/2007 10:26:13 AM
Carlos Moreno wrote:
> JohnQ wrote:
>
> > Why have more threads than the number of processor cores?
>
> I'm baffled by this question ...
>
> The above question is exactly equivalent to "why would we want
> multithreading?"

Not at all. I was just wondering why/when that "rule" should be
used. Is it whenever you want two or more tasks to APPEAR to
be running at the same time rather wanting to get the most
work done per core? For example: GUI prog, use as many as
your heart desires; Database server: limit to the number of cores.

> If you're talking about CPU-bound tasks, then yes, multithreading
> doesn't make sense (for single-CPU machines), and with multi-
> core CPUs or SMP, it wouldn't make sense to have more threads
> than CPUs (or CPU cores)...  But from there to your question
> above, that's a bit of a stretch, don't you think?

Nope.

John


--
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
JQP
1/11/2007 10:34:03 AM
Mathias Gaunard wrote:
> JohnQ wrote:
>
> > Doesn't ACE attempt to provide a wrapper across current platforms?
>
> There is also boost.thread, which is very similar to what will be
> provided by the C++ standard.
>
> It follows the POSIX C model.

Thanks for the warning.  ;)

> > That sounds wrought with peril given the discussions here lately.
> > Probably better to be platform-specific at this juncture.
>
> For today, just depend on POSIX.
> However, POSIX doesn't define everything for C++, since it is for C.

And I like the Windows abstractions better than the POSIX ones. And
putting that non-native layer on top of the Windowsisms may make it
more likely that one of those pesky compiler behaviors that are being
discussed might ruin the show (?).

John


--
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
JQP
1/11/2007 10:34:36 AM
Carlos Moreno wrote:
> JohnQ wrote:

> > Why have more threads than the number of processor cores?

> I'm baffled by this question ...

> The above question is exactly equivalent to "why would we want
> multithreading?"

Not exactly.  One of the reason some people (particularly in the
numeric processing community) want threads is precisely to
spread the work out across multiple CPU's, so that it can be
done in parallel.  Having to break one loop into N smaller
loops, run them in separate threads, synchronize at the end and
merge the results is a lot of extra programmer work, and added
complexity, but if those N smaller loops run in parallel on
different CPU's, the results can be a lot, lot faster.  (You
won't speed things up by a factor of N, because of the added
overhead of synchronization, but if N == 256, if done correctly,
you can often achieve a speed up of a factor of 200 or more.)

Of course, that's not the only reason people use multiple
threads.

> If you have several things to do in the morning (like, right
> after waking up and going to work), such as making coffee;
> a process in which you turn on a switch, and your machine
> does everything else --- albeit, taking three minutes before
> it's finished;  then, you just have to grab a cup/mug and pour
> the coffee and drink it, turn on the TV to see the weather
> forecast (or firing up your PC and connect to whatever dot
> com you use for the weather), and then iron your shirt... Just
> because you have a single body (single brain, single pair of
> hands, etc.), would you force yourself to do those tasks
> sequentially??  Would you refuse to go check the weather during
> the three minutes that the coffee machine is taking to finish
> your coffee?

Except that you don't necessarily need multi-threading for that.

The advantage with regards to multithreading involves state.
For multithreading to be useful in such cases, it is necessary
that 1) individual operations involve a number of "blocking"
operations---operations where the code is just waiting on
something else---, 2) that the operations involve
significant state, especially if that state controls the
workflow of the operation, and 3) that separate operations share
significant in-memory data.  Without the first, you don't gain
anything (unless there are multiple cores) compared to just
executing the operations sequentially (although in certain
cases, especially if one thread had higher precedence, you might
gain in reactivity).  Without the second, there's no reason not
to return to the main wait loop for each wait---GUI programs did
this for years.  Without the third, you're probably better off
using separate processes, rather than threads.

Of course, other considerations can be involved.  I already
mentionned the reactivity one: even if processing the last click
requires 10 or 20 seconds raw CPU, you want to be able to redraw
the window if it is covered and then uncovered.  Robustness and
reliability also plays a role: sharing state between processes
is more complex (and slower) than sharing it between threads,
but if one process core dumps, the others go on working, and if
you are explicitly managing the state, returning to the main
loop for each wait, synchronization is much, much simpler, and
you don't have nearly as much risk of a deadlock or a race
condition.

--
James Kanze (GABI Software)             email:james.kanze@gmail.com
Conseils en informatique orientie objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place Simard, 78210 St.-Cyr-l'Icole, France, +33 (0)1 30 23 00 34


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
James
1/11/2007 3:09:21 PM
Mathias Gaunard wrote:
> JohnQ wrote:

> > Doesn't ACE attempt to provide a wrapper across current platforms?

> There is also boost.thread, which is very similar to what will be
> provided by the C++ standard.

> It follows the POSIX C model.

Not entirely.  The threading model is fairly close to a subset
of the Posix threading model.  There's no relationship to
anything C'ish in it, however, and large parts of the Posix
threading model (thread cancellation, rwlocks, thread local
memory, etc.) are ignored.

> > That sounds wrought with peril given the discussions here lately.
> > Probably better to be platform-specific at this juncture.

> For today, just depend on POSIX.

Rather difficult, if you have to program under Windows.  Also
rather difficult if you want to use all of C++: Posix doesn't
say anything about destructors, local static variables, const
functions vs. non-const, etc., etc.  (If you ban destructors,
dynamic initialization for local static variables, exceptions
and const functions, you probably do have enough guarantees.)

> However, POSIX doesn't define everything for C++, since it is
> for C.

Right.  And not all systems are Posix compliant, either.

--
James Kanze (GABI Software)             email:james.kanze@gmail.com
Conseils en informatique orientie objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place Simard, 78210 St.-Cyr-l'Icole, France, +33 (0)1 30 23 00 34


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
James
1/11/2007 3:09:51 PM
Pete Becker wrote:
> Not quite. There are two different perspectives on multi-threaded
> programming. On is "distribute the workload optimally among the
> available processors." That's when you want just as many threads as
> processor cores. The other is "logically divide the process into tasks
> that can be run concurrently." That's when you want as many threads as
> appropriate, and are willing to put up with some thrashing and delays
> when you have more threads than cores.
>
	OK, what about "logically divide the process into jobs that can be
run
concurrently" and put them on the thread pool's queue?
--
         With all respect, Sergey.               http://ders.stml.net/
         mailto : ders at skeptik.net

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Sergey
1/11/2007 3:11:14 PM
JohnQ wrote:
> "Le Chaud Lapin" <jaibuduvin@gmail.com> wrote in message
> news:1168399666.909953.168890@p59g2000hsd.googlegroups.com...
> > JohnQ wrote:
> >> The threads of discussion about threads have been enlightening in
> >> exposing
> >> some of the low level issues which could possibly affect MT code and,
> >> more importantly, served also to bring awareness to the unsuspecting
(me
> >> for one). It leaves me wondering if writing MT code is even to be
pursued
> >> at this point in time, or at least "where's the guidebook to read is
that
> >> will
> >> facilitate the writing of MT code without engaging compiler-level
> >> gotchas?". Can the low level issues be dealt with in the short term by
> >> following certain rules, perhaps platform-specific ones, or is robust
MT
> >> code not a possibility at all at this time? Are the low level issues
just
> >> ones
> >> of portability and therefor all those MT Windows programs developed
> >> over the last few years, for example, can be considered probably OK in
> >> regards to those compiler-level issues?

> > IMO, you can write robust multi-threading applications today that work
> > on the major operating systems (Windows, Unix, etc.)

> Well obviously anyone who's been reading the thread threads knows that
> is what you think!

Of course, he hasn't actually tried to do it:-).  My experience
is that you can write robust multi-threaded applications for a
specific implementation, but that they won't be portable.  (And
the API is the least of your problems.)

> >  And yes, the
> > issues are primarily related to finding a common API that more or less
> > remains constant and making sure that the OS designer has provided a
> > sufficient set of kernel-mode primitives.

> Doesn't ACE attempt to provide a wrapper across current platforms?
> That sounds wrought with peril given the discussions here lately.
> Probably better to be platform-specific at this juncture.

That's why there's an attempt to standardize.  (FWIW: I gave up
on ACE because I found too many errors and false assumptions in
it.)

> It be nice for the compiler guys at Microsoft to chime in and say that
> they've thought about issues brought up here and get them to say
> absolutely say yes or no as to whether there are potential dangers and
> what they are.

The problem is that it is "guys", and not just "guy".  As with
most big companies, you often get cases where the left hand
doesn't know what the right hand is doing.  In the case of
Microsoft, there are definitly people in the technical pars of
the company who have taken all of the points mentionned so far
into consideration, both in the OS group (working on Windows),
and in the compiler group.  I'm less sure that the people in
documentation are as up on the issues, so it's possible that the
guarantees aren't correctly documented.

> I know that after following the thread threads I'm not going
> to be turning on the optimization flags on the compiler anytime soon for
> one thing.

A good policy even in single threaded code.  Until you need the
performance they give.

> > With my own projects, I decided to familiarize myself with the
> > synchronization primitives on one platform (Windows), knowing that, if
> > the engineers "thought it through" enough, then most likely, there will
> > be parallel primitives on the other platforms.  Many of the people who
> > did the Windows kernel-mode work came from VMS (I heard),

> And with VMS being a realtime OS, that bodes well.

I don't think that there's any doubt as to the competence of the
people implementing Windows, nor of their awareness of the
issues.  But that's no proof that the got everything right,
either.

> > which
> > probably explains why I have been so pleasantly surprised that they did
> > "think it through" in times of doubt. (PulseEvent notwithstanding).
> > IBM wrote a series of articles for porting multi-threaded applications
> > that will help get a broad overview of who is doing what. Things like
> > named kernel-mode primitives can be highly useful, and have been with
> > Windows for a long time, but not so long on Linux.  What would help is
> > help is to have a comprehensive set of kernel-mode primitives across
> > all OSes, but of course, this can force the question of what is
> > fundamental and what is not, for example, with whether there should be
> > real, bona-fide, intra-process threads. [Yes on Windows, Not Always on
> > Unix].

> Well get the UNIX folks to pick up on the Windowisms is not going to
> happen (though I personally wish it would because that's where I'm
> from).

FWIW: the person who developped Boost::threads comes from a
strong Windows background.  He adopted a model based on Posix
because he found it significantly superior.  (That is, at least,
what I have been told.  And from the Boost::threads
documentation: "Event variables are simply far too error-prone.
boost::condition variables are a much safer alternative.")  It's
also significant that Vista adopts condition variables; this may
be only because they feel certain that that will be the model
adopted by the C++ standard, and not for any particular
technical reasons.  And the Boost library does implement
condition variables under Windows, using Windows OS primitives,
so it must be possible.

> > http://www-128.ibm.com/developerworks/library/l-ipc2lin2.html

> > I wrote a C++ wrapper framework that encapsulates the OS primitives on
> > Windows.  Naturally, this implies that one has thought about usage
> > patterns of synchronization in multi-threaded applications, which,
> > while not too difficult for the easier primitives like events, mutexes,
> > and semaphores,...becomes a bit harder when you try to make a "thread
> > class".  Many programmers have tried to make "thread classes" only to
> > find that there is a severe penalty for choosing a wrong conceptual
> > model.

> What kind of penalty? Performance or constrained design possibilities?

Probably both.

> > I fell into this trap.  The best advice I can give in this
> > regard is to say that the concept of the thread itself should not be
> > modeled as a class.

> That's exactly how I did it years ago. That's probably where I'd start
> from again if/when I dust off and revive that code. I was probably
> influenced by the Borland class library and maybe even MFC. So
> you think they got it wrong huh?

There are two philosophies: a thread is an asynchronous
function, or a thread is a class.  The Boost model tries for a
sort of compromize between the two: a thread is a class, but one
that acts like an implicitly called functional object, and whose
lifetime doesn't need to extend to the lifetime of the entire
thread.

In my own work, I distinguish between joinable threads and those
that you "fire and forget".  Joinable threads are a class, so
you have something to join with; detached threads are started by
a simple function call.

Another philosophy involves "futures": basically, it consists of
a function to start the thread; the function returns an object
which can later be used for joins.

And of course, it's arguable whether one can even use detached
threads in a correct program.  It certainly makes clean shutdown
more difficult.  (On the other hand, many of my programs run
forever, so this isn't an issue.)

Anyhow, as you can see, this is an area where there is very
little, if any, consensus.  (At least there is a consensus in
the committee that you must also be able to use system level
threads, i.e. that whether you start the thread using the
"standard" way, or a low level system call, all of the other
threading guarantees hold, you can still synchronize with
standard mutexes, etc.)

> > The other best advice I can give, by far, is not to underestimate
> > WaitForMultipleObjects on Windows and its equivalents on other OSes.

> Why would anyone "underestimate" that? My guess is you're talking
> about those who have a UNIX/POSIX background right?

I suspect that most of the people who "underestimate" it simply
know how easy it is to provide, given the basic threading
primitives.  There seems to be a consensus amongst the threading
experts that only two primitive objects, mutexes and condition
variables, are necessary.  Everything else can be implemented in
terms of them.  (Of course, it's nice to have it already done
for you, and I was quite happy to use rwlocks when I needed
them, without having to implement them myself using mutexes and
condition variables; even if I know how, it's more code to
write and to maintain.)

Glancing through the Windows documentation, my impression is
that in addition to condition variables, it is missing some way
of statically initializing mutexes.  This would seem essential
to me in order to maintain encapsulation (and well over half of
my pthread_mutex_t are statically initialized).  This would be
less of a problem if the compiler allows unsynchronized use of
local static variables with dynamic initialization, but since
one of my target compilers (Sun CC) doesn't, I can't take
advantage of it.

Ideally, you also want some means of signaling a thread that you
want it to shutdown, along the lines of pthread_cancel.  I
haven't seen an equivalent in Windows, and of course, the
semantics of pthread_cancel are not defined in C++ (and
different compilers define them differently), which doesn't help
either.  (I might add that there has been enough discussion in
the C++ committee to make me think that there isn't really any
consensus as to what the semantics should be.)  In the meantime,
you have to improvise, using some sort of global flag, and
ensuring that no thread does an indefinitly blocking call.
(This typically means that you can't use std::cin.)

--
James Kanze (GABI Software)             email:james.kanze@gmail.com
Conseils en informatique orientie objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place Simard, 78210 St.-Cyr-l'Icole, France, +33 (0)1 30 23 00 34


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
James
1/11/2007 3:13:07 PM
JohnQ wrote:
> "Le Chaud Lapin" <jaibuduvin@gmail.com> wrote
[...]

> 
>>which
>>probably explains why I have been so pleasantly surprised that they did
>>"think it through" in times of doubt. (PulseEvent notwithstanding).
>>IBM wrote a series of articles for porting multi-threaded applications
>>that will help get a broad overview of who is doing what. Things like
>>named kernel-mode primitives can be highly useful, and have been with
>>Windows for a long time, but not so long on Linux.  What would help is
>>help is to have a comprehensive set of kernel-mode primitives across
>>all OSes, but of course, this can force the question of what is
>>fundamental and what is not, for example, with whether there should be
>>real, bona-fide, intra-process threads. [Yes on Windows, Not Always on
>>Unix].
> 
> 
> Well get the UNIX folks to pick up on the Windowisms is not going to
> happen (though I personally wish it would because that's where I'm
> from).



Probably not but not for the reasons you think.  One, Microsoft is
a single organization.  Posix is a committee of various unix vendors
for the most part and compatibility is important and tends to slow
down progress.  You can't just mandate radical changes to everyone's
kernel and expect a majority vote from the committee.

The other is the Posix synchronization primative were architected to
allow efficient implementations without requiring kernel calls on
everything.  A Posix mutex is similar to a windows CriticalSection
for most implementations.  It's not a kernel object like windows
Mutex.  Windows CriticalSection and Mutex do the same thing but
the former is a lot faster.  But you can't use CriticalSections
in WaitForMultipleObjects because it's not a handle (kernel object) so
you have to use the slower Mutex instead.

The other problem with WaitForMultipleObjects, besides requiring expensive
kernel objects, is it basically requires GKL (giant kernel lock) to
correctly resolve synchronization events.  Literally "stop the world
so we can figure out whether some WaitForMultipleObjects is supposed to
succeed".  And the rules for that can be arcane.  You can have combinations
of transient events, non-transient events,  and synchronization with side
effects,
e.g. semaphores, mutexes, autoreset events, and other consumable events.
It's non trivial for a programmer to figure out how some complex
WaitForMultipleObjects are supposed to work.  Windows synchronization
objects
can be highly non-orthagonal.


> 
>>The other best advice I can give, by far, is not to underestimate
>>WaitForMultipleObjects on Windows and its equivalents on other OSes.
> 
> 
> Why would anyone "underestimate" that? My guess is you're talking
> about those who have a UNIX/POSIX background right?

You can overestimate it's value as well.  BTW, if you want that
kind of functionality, there's nothing to stop you from implmenting
it at the library level.  You have to use some form of listener pattern
and GLL (giant library lock) to correctly resolve wait conditions.
The only problem is you won't be able to ignore what a performance
pig it will be as well as you could if it was hidden in the kernel.



-- 
Joe Seigh

When you get lemons, you make lemonade.
When you get hardware, you make software. 

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Joe
1/11/2007 3:15:31 PM
Le Chaud Lapin wrote:
> JohnQ wrote:
> [snippage]

> > Well get the UNIX folks to pick up on the Windowisms is not going to
> > happen (though I personally wish it would because that's where I'm
> > from).

> I had more experience with Windows than Unix for a long time until
> length of time with Windows overtook length of time with Unix.  I never
> thought I would say it, but the thought of not having bona-fide threads
> is frightening.  I wonder if there will ever be convergence on things
> like this (file system being another example).

There is already some convergence: Vista has adopted parts of
the Posix model.  And Posix is vague enough to allow several
different underlying implementations; at least one of the Linux
threading implementations isn't that far from the Windows way of
doing things (although the Posix level interface doesn't always
make it that obvious).

> Or asked another way,
> "Are there fundamental themes that are universal, like the notion of a
> stack?"

There are several fundamental themes.  The problem is that some
of them are mutually exclusive, and until recently, threads
weren't widely enough used to be able to judge from experience
what was best.

> Design possibilities and structural sensibility.  I forget the
> thought-process I went through while making my thread frame work, but I
> did go deep into the rat hole.  When I came out, I concluded that you
> should use explicit new() and delete() to make thread "objects".  Mirek
> Fidler apparently has an alternative model that uses full-blown RAII.

Traditional models tied thread lifetime to a "thread" object.
This creates some fairly complex lifetime of object issues for
detached threads.

> > > The other best advice I can give, by far, is not to underestimate
> > > WaitForMultipleObjects on Windows and its equivalents on other OSes.

> > Why would anyone "underestimate" that? My guess is you're talking
> > about those who have a UNIX/POSIX background right?

> Or even Windows.  I went for a long while just using
> WaitForSingleObject, with an occasional timeout.  But there are moments
> when you are designing a system that, even thought it works, it simply
> does not feel quite right.  In this case, I heard myself saying, "Ok,
> this works, but it's ugly.  Too bad there is no way to wait for many
> things at same time...that is..." Then I remembered
> WaitForMultipleObjects.  I wrapped it and integrated it into the
> framework.  I used my Event, Mutex, Semaphore, List<> and Set<> classes
> to work with it..and in one afternoon, got rid of all the timeout
> values that I had been using for WaitForMultipleObjects.  One function
> shrunk in size from 800 lines to 300.  And the code made sense.  Of
> course, Microsoft's limitation of handles let you only wait for 32, but
> so far, I wait on maybe 7 or 8 objects at once.  And it is all in C++.
> As you can guess, I am really excited about this.  Finally, blocking
> can really be blocking, indefinitely, instead of say, for 8 hours then
> checking to see if you are hung.

But it is so simple to emulate.  Just start a thread for each
thing you want to wait for, which posts a message in a queue
when that event arrives, and wait on the queue in the main
thread.  (But I agree that it is nice for the system to do it
for you.)

--
James Kanze (GABI Software)             email:james.kanze@gmail.com
Conseils en informatique orientie objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place Simard, 78210 St.-Cyr-l'Icole, France, +33 (0)1 30 23 00 34


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
James
1/11/2007 3:16:02 PM
Le Chaud Lapin wrote:
> JohnQ wrote:
> > "Le Chaud Lapin" <jaibuduvin@gmail.com> wrote in message
> > news:1168399666.909953.168890@p59g2000hsd.googlegroups.com...
> > > JohnQ wrote:
> > Doesn't ACE attempt to provide a wrapper across current platforms?
> > That sounds wrought with peril given the discussions here lately.
> > Probably better to be platform-specific at this juncture.
>
> Not sure.  Incidentally, there s a strong parallel between the type of
> work I do and parts of ACE.  I will take a look.
>
> [snippage]
>
> > Well get the UNIX folks to pick up on the Windowisms is not going to
> > happen (though I personally wish it would because that's where I'm
> > from).
>
> I had more experience with Windows than Unix for a long time until
> length of time with Windows overtook length of time with Unix.

(Juxtaposition noted).

> I never
> thought I would say it, but the thought of not having bona-fide threads
> is frightening.

And by that you mean on any other platform or that either Windows or
UNIX is lacking them? By "bona-fide" threads, do you mean real threads
rather than something like pthreads?

> I wonder if there will ever be convergence on things
> like this (file system being another example).  Or asked another way,
> "Are there fundamental themes that are universal, like the notion of a
> stack?"

Well if you meant like a stack container rather than a memory stack,
well either way, I don't think so. Maybe at some least common
denominator level or across certain subsets of platforms, but then
there's new technologies, maybe like the filesystem in Open Solaris,
that is perhaps too different to be constrained into a common API. Even
if there were, someone is not going to like the way someone else did it
and will roll their own. (I know you posed the question rhetorically).

> > > I wrote a C++ wrapper framework that encapsulates the OS primitives on
> > > Windows.  Naturally, this implies that one has thought about usage
> > > patterns of synchronization in multi-threaded applications, which,
> > > while not too difficult for the easier primitives like events,
mutexes,
> > > and semaphores,...becomes a bit harder when you try to make a "thread
> > > class".  Many programmers have tried to make "thread classes" only to
> > > find that there is a severe penalty for choosing a wrong conceptual
> > > model.
> >
> > What kind of penalty? Performance or constrained design possibilities?
>
> Design possibilities and structural sensibility.  I forget the
> thought-process I went through while making my thread frame work, but I
> did go deep into the rat hole.  When I came out, I concluded that you
> should use explicit new() and delete() to make thread "objects".  Mirek
> Fidler apparently has an alternative model that uses full-blown RAII.

explicit new() and delete() as opposed to.... what? As opposed to being
wrapped up in one of your "Yin/Yang" classes? Please give a tiny
example of what you mean by "Yin/Yang" class. I tend to think of
yin/yang as sort of an equal and opposite reaction, or better,
completion of something. Complementary: not the same and not the
opposite, but complementary. So are you just wrapping new and delete of
an object in a constructor and destructor of a wrapper class?

> > That's exactly how I did it years ago. That's probably where I'd start
> > from again if/when I dust off and revive that code. I was probably
> > influenced by the Borland class library and maybe even MFC. So
> > you think they got it wrong huh?
>
> It seemed so.  Of course, I did not just make a thread class.  I tried
> to think about it from a systemic point of view.  For example, thread
> cancellation with orderly shutdown of that thread is desirable.

Well that could be put into a thread class (orderly shutdown). Indeed
that would be a reason to wrap the platform abstraction. But yes, other
threading things like locks are the obvious ones to wrap up (one of
mine is called AutoLock which wraps a mutex).

> I
> might be nice to wait for a thread to die.  It might be nice to wait
> for an event, three mutexes, a semaphore, and 2 threads to die, or any
> one of these things to be signaled, etc.    I was able to make all
> classes RAII, Yin/Yang style (mutexes, etc) except the thread class.

And the reason you couldn't make an RAII-style thread class is....?

> > > The other best advice I can give, by far, is not to underestimate
> > > WaitForMultipleObjects on Windows and its equivalents on other OSes.
> >
> > Why would anyone "underestimate" that? My guess is you're talking
> > about those who have a UNIX/POSIX background right?
>
> Or even Windows.  I went for a long while just using
> WaitForSingleObject, with an occasional timeout.  But there are moments
> when you are designing a system that, even thought it works, it simply
> does not feel quite right.  In this case, I heard myself saying, "Ok,
> this works, but it's ugly.  Too bad there is no way to wait for many
> things at same time...that is..." Then I remembered
> WaitForMultipleObjects.  I wrapped it and integrated it into the
> framework.  I used my Event, Mutex, Semaphore, List<> and Set<> classes
> to work with it..and in one afternoon, got rid of all the timeout
> values that I had been using for WaitForMultipleObjects.  One function
> shrunk in size from 800 lines to 300.  And the code made sense.  Of
> course, Microsoft's limitation of handles let you only wait for 32, but
> so far, I wait on maybe 7 or 8 objects at once.  And it is all in C++.
> As you can guess, I am really excited about this.  Finally, blocking
> can really be blocking, indefinitely, instead of say, for 8 hours then
> checking to see if you are hung.

Well I'm happy for you that you found the WaitForMultipleObjects
function. Are you enamouring about it here because you think most
people here are UNIX developers? Am I missing something about how you
are using WaitForMultipleObjects that is remarkably different than what
it was designed to do?

> > > It provides significant mental relief while design systems where many
> > > different things are happening at once and all need to be waited on by
> > > multiple threads, and yet still, you want to have the confidence that
> > > the design is will scale no matter how many global objects you have an
> > > no matter how many threads you have running (within reason).  For
> > > example, 25 global  objects with, say, 20 distinct threads, each
thread
> > > operating on 3 or 4 of the global objects, would be easy conceptually
> > > with WaitForMultipleObjects, but could quickly turn into a quagmire if
> > > trying to accomplish the same thing with WaitForSingleObject and
> > > time-outs.
> >
> > Why have more threads than the number of processor cores?
>
> The threads are not simply replicas of thread T, they are T, U, V, W,
> and Z, all different.  At any given time most, if not all, are in
> wait-state, consuming essentially no quanta.

I see. I was asking a bit facetiously to bring up the points about when
1 thread per core is warranted over more than that.

John


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
JQP
1/11/2007 3:19:45 PM
James Kanze wrote:

> however, and large parts of the Posix
> threading model (thread cancellation, rwlocks, thread local
> memory, etc.) are ignored.

boost.thread does provide thread local storage. There had been work done 
on read/write mutexes and locks, but I don't know what happened to that.


>> For today, just depend on POSIX.
> 
> Rather difficult, if you have to program under Windows.

For what reason?
Since there exists an implementation of the POSIX threads C library for 
MS Windows, I had assumed the OS and compilers already gave the same 
guarantees about threading than POSIX.

I don't really have much knowledge about the subject though.


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Mathias
1/11/2007 9:33:09 PM
James Kanze wrote:

>>>Why have more threads than the number of processor cores?
> 
>>I'm baffled by this question ...
> 
>>The above question is exactly equivalent to "why would we want
>>multithreading?"
> 
> Not exactly.  One of the reason some people (particularly in the
> numeric processing community) want threads is precisely to
> spread the work out across multiple CPU's, so that it can be
> done in parallel.  [ ...... ] 

Ok, James, and Pete...

I don't mean to go all schoolyard on you, but...  How is what
you're saying any different from what I said?  (other than
zooming-in on one aspect?) --- or in any case, how does it
contradict it?

The question "why have more threads than CPU cores?", the way
I read/understand it, means that he implies that having more
threads than CPU cores does not make sense, and is inviting
us to convince him otherwise --- but that statement, without
any qualification, is incorrect;  in *one particular subset*
of the cases, having more threads than CPUs does not make
sense;  but his comment has broad coverage  (again, maybe
I'm reading it too "literally/strictly"?)

I did talk about CPU-bound tasks, in which, as you also point
out, threads only makes sense as a means of spreading the
task among the available CPUs;  but my analogy with several
tasks (making the coffee, checking the news, the weather
forecast, ironing your shirt, etc.) is precisely a very close
analogy for IO-bound tasks  (as you point out, processes in
which the CPU spends lots of time doing nothing because it
has to wait for some slow, "external" task to be completed).

I also did imply the part of additional requirements to make
the use of threads worthwhile (the fact that independent
tasks have state to keep track of --- otherwise, a loop
that sequenctially checks flags to continue with certain
tasks would be equally efficient/attractive);  I didn't
want to expand too much on it, since I thought it was quite
obvious what my point was  (contradicting a statement that
was stated in general, when it only applies to *one specific
type of situation*, those in which you have CPU-intensive
tasks and have the opportunity to speed them up by muli-
threading among multiple CPU cores or multiple CPUs on an
SMP architecture)

Carlos
--

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Carlos
1/11/2007 11:58:46 PM
Carlos Moreno wrote:
> James Kanze wrote:
> 
>>>> Why have more threads than the number of processor cores?
>>
>>> I'm baffled by this question ...
>>
>>> The above question is exactly equivalent to "why would we want
>>> multithreading?"
>>
>> Not exactly.  One of the reason some people (particularly in the
>> numeric processing community) want threads is precisely to
>> spread the work out across multiple CPU's, so that it can be
>> done in parallel.  [ ...... ] 
> 
> Ok, James, and Pete...
> 
> I don't mean to go all schoolyard on you, but...  How is what
> you're saying any different from what I said?  (other than
> zooming-in on one aspect?) --- or in any case, how does it
> contradict it?
> 

I didn't read the last paragraph of your earlier message, which does,
indeed, talk about CPU-bound tasks and running one per core. If I had I
might not have responded as I did. But you have to admit, "exactly
equivalent" is a bit of an overstatement. <g>

-- 

	-- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Pete
1/12/2007 6:52:53 AM
JQP wrote:
> Carlos Moreno wrote:
> > JohnQ wrote:
> >
> > > Why have more threads than the number of processor cores?
> >
> > I'm baffled by this question ...
> >
> > The above question is exactly equivalent to "why would we want
> > multithreading?"
>
> Not at all. I was just wondering why/when that "rule" should be
> used. Is it whenever you want two or more tasks to APPEAR to
> be running at the same time rather wanting to get the most
> work done per core? For example: GUI prog, use as many as
> your heart desires; Database server: limit to the number of cores.

Pretty much, except that you want the number of _running_ threads to be
(approximately) equal to the number of cores.


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Peter
1/12/2007 6:54:32 AM
JQP wrote:
> Le Chaud Lapin wrote:
> > I never
> > thought I would say it, but the thought of not having bona-fide threads
> > is frightening.
> And by that you mean on any other platform or that either Windows or
> UNIX is lacking them? By "bona-fide" threads, do you mean real threads
> rather than something like pthreads?

Yes and yes. My system model will fall apart on an OS that does not
have threads.  For example, I remember trying to choose between Windows
CE and PalmOs for a "small device" test system.  When I saw that Palm
OS did not have multi-tasking, the answer was easy.  They do have
Cobalt now, but to not have had it before says something about the OS.
Also, for a while, creating threads in Unix was not as simple as doing
a CreateThread.  The newer models like LWP seem to have helped a lot.

> > Design possibilities and structural sensibility.  I forget the
> > thought-process I went through while making my thread frame work, but I
> > did go deep into the rat hole.  When I came out, I concluded that you
> > should use explicit new() and delete() to make thread "objects".  Mirek
> > Fidler apparently has an alternative model that uses full-blown RAII.
>
> explicit new() and delete() as opposed to.... what? As opposed to being
> wrapped up in one of your "Yin/Yang" classes? Please give a tiny
> example of what you mean by "Yin/Yang" class. I tend to think of
> yin/yang as sort of an equal and opposite reaction, or better,
> completion of something. Complementary: not the same and not the
> opposite, but complementary. So are you just wrapping new and delete of
> an object in a constructor and destructor of a wrapper class?

Yin/Yang in the context of my thread class is equivalent to RAII.
CreateThread is in the constructor, and CloseHandle is in the
destructor (effectively).  Normally, I make most of my objects
copyable, but decided that it was not appropriate to make thread object
copyable.  My containers assume copyability, so I had to use pointers
to objects in the container: new()ed.

> > It seemed so.  Of course, I did not just make a thread class.  I tried
> > to think about it from a systemic point of view.  For example, thread
> > cancellation with orderly shutdown of that thread is desirable.
>
> Well that could be put into a thread class (orderly shutdown). Indeed
> that would be a reason to wrap the platform abstraction. But yes, other
> threading things like locks are the obvious ones to wrap up (one of
> mine is called AutoLock which wraps a mutex).

Yep.  My thread class includes as part of its design a mechanism for
orderly shutdown.  I would not be surprised if the code is the same.

> > might be nice to wait for a thread to die.  It might be nice to wait
> > for an event, three mutexes, a semaphore, and 2 threads to die, or any
> > one of these things to be signaled, etc.    I was able to make all
> > classes RAII, Yin/Yang style (mutexes, etc) except the thread class.
>
> And the reason you couldn't make an RAII-style thread class is....?

Honestly, I cannot remember.  I has been a while since I worked on the
synchronization part of my library.  I do remember that making the
thread class copyable was not good.  Cannot remember why.  My brain
cycles have been usurped by crypto over last few weeks.

> Well I'm happy for you that you found the WaitForMultipleObjects
> function. Are you enamouring about it here because you think most
> people here are UNIX developers? Am I missing something about how you
> are using WaitForMultipleObjects that is remarkably different than what
> it was designed to do?

No, not really. I am not adding anything new in terms of functionality.
 There were many places in my code where I needed to wait for multiple
things, but could not block indefinitely, so I would have to wait "a
long time", but "not too long", using time-outs on WaitForSingleObject.
 Those time-outs are all gone now, and I really can "block
indefinitely" waiting for 5 or 6 things of various kinds (events,
mutexes), etc. to happen at one.  The framework is not necessarily
bound to the Windows model, so it looks like portable C++.

> I see. I was asking a bit facetiously to bring up the points about when
> 1 thread per core is warranted over more than that.

Should be interesting one day to share system designs. ;)

-Le Chaud Lapin-


--
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Le
1/12/2007 10:37:14 AM
Carlos Moreno wrote:
> James Kanze wrote:
>
> >>>Why have more threads than the number of processor cores?
> >
> >>I'm baffled by this question ...
> >
> >>The above question is exactly equivalent to "why would we want
> >>multithreading?"
> >
> > Not exactly.  One of the reason some people (particularly in the
> > numeric processing community) want threads is precisely to
> > spread the work out across multiple CPU's, so that it can be
> > done in parallel.  [ ...... ]
>
> Ok, James, and Pete...
>
> I don't mean to go all schoolyard on you, but...  How is what
> you're saying any different from what I said?  (other than
> zooming-in on one aspect?) --- or in any case, how does it
> contradict it?
>
> The question "why have more threads than CPU cores?", the way
> I read/understand it, means that he implies that having more
> threads than CPU cores does not make sense, and is inviting
> us to convince him otherwise --- but that statement, without
> any qualification, is incorrect;  in *one particular subset*
> of the cases, having more threads than CPUs does not make
> sense;  but his comment has broad coverage  (again, maybe
> I'm reading it too "literally/strictly"?)

I meant it like that but a bit facetiously as I wanted reinforcement of
the scenarios where more are better and where they're not.

John


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
JQP
1/12/2007 2:42:37 PM
In article <1168399666.909953.168890@p59g2000hsd.googlegroups.com>, Le 
Chaud Lapin <jaibuduvin@gmail.com> writes
>IMO, you can write robust multi-threading applications today that work
>on the major operating systems (Windows, Unix, etc.)
Several years ago Herb Sutter stated in a keynote at an ACCU Spring 
Conference that in his experience/opinion multithreaded code ran 
correctly through luck rather than design. He expected that with the 
advent of multiprocessor/core hardware that programs would fail 
erratically.

There is an implicit assumption in much MT code that the code will run 
sequentially even if in an unspecified order.

One particularly difficult issue with MT is that it is close to 
impossible to prove the correctness of the code unless it is so tied 
down by locks that it might just as well be single threaded.

What concerns me is that we may give too much weight to the last decades 
experience of writing MT code to run on single processors and ignore the 
wealth of experience of those who program for large multi-processor 
machines (who largely do not contribute to discussions about C++ for a 
variety of reasons, one of which is that they have too often been 
ignored in the past.)

MT code that has run correctly on a single processor is no evidence that 
it will do so when compiled for a multi-processor/core machine. Indeed 
correct running on older hardware is no evidence that the code is 
actually correct (as I discovered a couple of years ago when a piece of 
code that had run successfully for several years suddenly started 
falling over consistently -- on investigation the problem was found to 
be in a library function that was vulnerable to a timing issue, the 
increased speed of the CPU had triggered the problem)

I suspect that many programmers confidence in their code is soon going 
to be shown to be over-confidence. I would be happy to be wrong ... but 
somehow I doubt that I am.

-- 
Francis Glassborow      ACCU
Author of 'You Can Do It!' and "You Can Program in C++"
see http://www.spellen.org/youcandoit
For project ideas and contributions:
http://www.spellen.org/youcandoit/projects


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Francis
1/12/2007 3:19:49 PM
In article <cX8ph.93555$fg.1257215@weber.videotron.net>, Carlos Moreno 
<moreno_at_mochima_dot_com@mailinator.com> writes
>If you have several things to do in the morning (like, right
>after waking up and going to work), such as making coffee;
>a process in which you turn on a switch, and your machine
>does everything else --- albeit, taking three minutes before
>it's finished;  then, you just have to grab a cup/mug and pour
>the coffee and drink it, turn on the TV to see the weather
>forecast (or firing up your PC and connect to whatever dot
>com you use for the weather), and then iron your shirt... Just
>because you have a single body (single brain, single pair of
>hands, etc.), would you force yourself to do those tasks
>sequentially??  Would you refuse to go check the weather during
>the three minutes that the coffee machine is taking to finish
>your coffee?
Not sure this is a good analogy. Each of the operations you describe 
above are effectively independent and make no demands on your brain 
apart from initiating start-up. Most MT code actively uses and shares 
the CPU resource as well as other resources.

Now consider what happens in the morning when you put the kettle on with 
sufficient water for your coffee and while you are checking the weather 
forecast your partner makes a cup of coffee. Unless you live by 
yourself, kettles, PCs etc. are usually shared resources :-) and we know 
what can happen ...

To answer your question, yes I do those things sequentially:

Fill kettle, plug in and turn on, turn on TV, iron shirt, make coffee. 
The point is that making coffee involves a number of 'atomic' tasks. And 
from experience I find that ironing a shirt is normally better treated 
as an atomic task (critical section? :-)

Of course, where the analogy further breaks down is that our brains are 
actually capable of a degree of parallel processing, I can drink coffee 
and read the weather forecast at the same time.

Now as regards C++, the current language is designed for the 'one person 
household' and now we are considering how to redesign it for a 
'multi-person household'.


-- 
Francis Glassborow      ACCU
Author of 'You Can Do It!' and "You Can Program in C++"
see http://www.spellen.org/youcandoit
For project ideas and contributions:
http://www.spellen.org/youcandoit/projects


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Francis
1/12/2007 3:23:30 PM
Mathias Gaunard wrote:
> Since there exists an implementation of the POSIX threads C library for
> MS Windows, I had assumed the OS and compilers already gave the same
> guarantees about threading than POSIX.
>
	Are you talking about http://sourceware.org/pthreads-win32? AFAICS
pthreads-win32 can be considered only as a path of least resistance for
POSIX->Win32 porting.
	Personally, I considered several ways for a portable C++ MTing and
've chosen
to write my own set of wrappers that doesn't have to emulate native XXX
quirks
on YYY system. This simple and robust solution addresses about 95% of my
current C++ MT needs.
--
         With all respect, Sergey.               http://ders.stml.net/
         mailto : ders at skeptik.net

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Sergey
1/12/2007 3:24:06 PM
Francis Glassborow wrote:
> One particularly difficult issue with MT is that it is close to 
> impossible to prove the correctness of the code unless it is so tied 
> down by locks that it might just as well be single threaded.

The hardest part about proving correctness of multi-threaded
programs is coming up with the proper assertions to prove.
Once you do that, the proof usually falls into place.  And
even that isn't as much of a problem as you might think it would
be.  If you use well known threaded design patterns, the assertions
would be known also and the proofs more or less already done by
someone else.  It becomes an exercise in confirming a proper
implementation of the threaded design pattern.  This applies
to lock-free thread patterns as well as lock based ones.
Just don't try to invent new patterns unless you know what you're
doing and/or like pain.

Of course you need to include the threaded design patterns as part
of the definition of synchronization functions and not rely on
mnemonics which can be misleading in subtle ways, e.g. "mutual
exclusion".


> 
> What concerns me is that we may give too much weight to the last decades 
> experience of writing MT code to run on single processors and ignore the 
> wealth of experience of those who program for large multi-processor 
> machines (who largely do not contribute to discussions about C++ for a 
> variety of reasons, one of which is that they have too often been 
> ignored in the past.)

That's alright.  We get ignored in c.p.t., also. :)


-- 
Joe Seigh

When you get lemons, you make lemonade.
When you get hardware, you make software. 

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Joe
1/12/2007 5:48:04 PM
Pete Becker wrote:

>>  [...]
>> Ok, James, and Pete...
>>
>> I don't mean to go all schoolyard on you, but...  How is what
>> you're saying any different from what I said?  (other than
>> zooming-in on one aspect?) --- or in any case, how does it
>> contradict it?
> 
> I didn't read the last paragraph of your earlier message, which does,
> indeed, talk about CPU-bound tasks and running one per core. If I had I
> might not have responded as I did. But you have to admit, "exactly
> equivalent" is a bit of an overstatement. <g>

Ok, I have to admit that it was (a bit of an overstatement) ....
(also, the previous poster apparently didn't mean that question
as strictly as I interpreted it, after all)

So we'll agree to dis...  No, wait, we're actually agreeing to
agree!!!  :-)

Cheers,

Carlos
--

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Carlos
1/13/2007 5:45:51 AM
JQP wrote:

> [...] For example: GUI prog, use as many as
> your heart desires; Database server: limit to the number of cores.

Why the principle applied to DB servers??  True that there is some
intensive work to be done, but I would expect that a portion of the
processing would be IO-bound  (yes, DB servers should optimize as
much as possible the access to be made from memory instead of from
disk, but it can't be 100% diskless).

I would definitely expect a DB server --- if taking advantage of
multithreading at all --- to have more running threads than the
available cores.

Anyway, yes, my comment qualifies as rather nit picking, as we
are in complete agreement in terms of the principle that you're
suggesting.  (plus, BTW, I may be wrong in my estimate about how
a DB server would make use of threads)

Carlos
--

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Carlos
1/13/2007 5:49:25 AM
Francis Glassborow wrote:

>> If you have several things to do in the morning (like, right
>> after waking up and going to work), such as making coffee;
>> a process in which you turn on a switch, and your machine
>> does everything else --- albeit, taking three minutes before
>> it's finished;  then, you just have to grab a cup/mug and pour
>> the coffee and drink it, turn on the TV to see the weather
>> forecast (or firing up your PC and connect to whatever dot
>> com you use for the weather), and then iron your shirt... Just
>> because you have a single body (single brain, single pair of
>> hands, etc.), would you force yourself to do those tasks
>> sequentially??  Would you refuse to go check the weather during
>> the three minutes that the coffee machine is taking to finish
>> your coffee?
> 
> Not sure this is a good analogy. Each of the operations you describe 
> above are effectively independent and make no demands on your brain 
> apart from initiating start-up. 

That's precisely the reason why it is a good analogy !!!

Keep in mind, I was contesting the idea that the only way that
multithreading can make sense is to have the same number of
running threads as available CPU cores  (a misinterpretation
from my part, as we later discussed --- or rather, a "too
literal/strict" interpretation).

Precisely because the tasks described above only require one's
brain attention to initiate the task (and actually we are in
a sense notified when the task finishes --- with the coffee,
for instance, it would not be a stretch to consider a coffee
machine that makes some noise/beep when the coffee is ready),
it makes sense to multithread --- taking advantage of what
would otherwise be wasted idle time, to use that *same* CPU
for other tasks.  IOW, multithreading by time slicing, when
that is possible  (which again, precisely the reason why I
still believe the analogy is good --- because it is an analogy
of the situations where multithreading by time slicing is
possible;  in this case, the notion of "possible" somewhat
implies the "possible while doing it effectively")

> Now consider what happens in the morning when you put the kettle on with 
> sufficient water for your coffee and while you are checking the weather 
> forecast your partner makes a cup of coffee. Unless you live by 
> yourself, kettles, PCs etc. are usually shared resources :-) 

Oh, not my coffee machine it isn't!!!  My wife knows that
messing with my coffee machine would be grounds for divorce! :-)

> Of course, where the analogy further breaks down is that our brains are 
> actually capable of a degree of parallel processing, I can drink coffee 
> and read the weather forecast at the same time.

Again, the analogy does not apply to this --- perhaps you
misinterpreted the context in which I was providing the
analogy?

> Now as regards C++, the current language is designed for the 'one person 
> household' and now we are considering how to redesign it for a 
> 'multi-person household'.

Absolutely necessary --- you have been quite eloquent in the
recent threads (as already said, no pun intended) about the
need of adding multithreading awareness to the language;  a
notion that I completely share  (as I would guess most C++
developers also share)

Carlos
-- 

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Carlos
1/13/2007 9:42:48 AM
"Carlos Moreno" <moreno_at_mochima_dot_com@mailinator.com> wrote in message
news:l2Vph.80252$9i3.367737@wagner.videotron.net...
> JQP wrote:
>
>> [...] For example: GUI prog, use as many as
>> your heart desires; Database server: limit to the number of cores.
>
> Why the principle applied to DB servers??

Someone emphasized the point that I should have said "limit the number of
RUNNING threads to the number of cores". As I think about that now, I
realize that it's impossible to have more threads running than the number of
cores (!). So, I think he meant that the number of ACTIVE threads (the ones
timeslicing the CPU) should be limited to the number of cores so as not to
incur the thread switching overhead. In light of that, I'll say that there
is no need to give the appearance of multiple DB transactions proceeding
along concurrently akin to indeed giving an analogous impression with GUIs.

I think the answer to your question is: because the goal is to get the most
work done in the least amount of time (maximize processing efficiency) and
that means minimizing the processing overhead (thread switching).

> True that there is some
> intensive work to be done, but I would expect that a portion of the
> processing would be IO-bound  (yes, DB servers should optimize as
> much as possible the access to be made from memory instead of from
> disk, but it can't be 100% diskless).

But it shouldn't be disk bound. That may mean you probably need a higher
performing storage subsystem. The goal is to service all requests in a
reasonable amount of time and avoid the following:

"Because of the high transaction volume we are encountering at this time,
your request could not be serviced. Please try again later. We regret any
and all inconvenience this may have caused and you should indeed demand
credit for the time the service was unavailable to you."

Saturating the disk subsystem is an exception (error) that must be handled
somehow (perhaps like above). Perhaps the disk subsystem was specified
incorrectly from the get go or maybe the transaction volume increased beyond
expectations before the system was upgraded to handle the higher volume. How
often such a thing can be tolerated and what the consequences are is
application-specific. I think that you have to design the database server
software program(s) first with the assumption that you have infinite disk
throughput. In that case, you want to do the "maximize efficiency by
minimizing overhead" thing by limiting the amount of thread switching
perhaps by limiting the number of active threads (whatever they may be
doing) to the number of processor cores. On top of that you build against
the "what if" scenarios.

> I would definitely expect a DB server --- if taking advantage of
> multithreading at all --- to have more running threads than the
> available cores.

Well in the scenario where the threads are in-progress transactions (not
long running ones), why would you want to switch between them and make small
progress toward completion of a bunch of them rather than taking a 1000 foot
view and seeing that more transactions are completed over the same period
time if the wasted CPU time used for switching threads is eliminated?

> Anyway, yes, my comment qualifies as rather nit picking, as we
> are in complete agreement in terms of the principle that you're
> suggesting.

> (plus, BTW, I may be wrong in my estimate about how
> a DB server would make use of threads)

Transactions modeled as thread objects from a threadpool perhaps? It's
contrived simplicity, but I think it shows the theory correctly (?).

John


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
JohnQ
1/13/2007 9:47:02 AM
"Peter Dimov" <pdimov@gmail.com> wrote in message
news:1168567134.727505.269630@v45g2000cwv.googlegroups.com...
> JQP wrote:
>> Carlos Moreno wrote:
>> > JohnQ wrote:
>> >
>> > > Why have more threads than the number of processor cores?
>> >
>> > I'm baffled by this question ...
>> >
>> > The above question is exactly equivalent to "why would we want
>> > multithreading?"
>>
>> Not at all. I was just wondering why/when that "rule" should be
>> used. Is it whenever you want two or more tasks to APPEAR to
>> be running at the same time rather wanting to get the most
>> work done per core? For example: GUI prog, use as many as
>> your heart desires; Database server: limit to the number of cores.
>
> Pretty much, except that you want the number of _running_ threads to be
> (approximately) equal to the number of cores.

That's all that CAN run (#of RUNNING threads = # of cores). Limiting the
number of ACTIVE threads to the number of cores should increase efficiency
by eliminating thread switching. Probably what you meant (?).

John


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
JohnQ
1/13/2007 9:47:48 AM
James Kanze wrote:
> JohnQ wrote:
> > "Le Chaud Lapin" <jaibuduvin@gmail.com> wrote :

> > > I wrote a C++ wrapper framework that encapsulates the OS primitives on
> > > Windows.  Naturally, this implies that one has thought about usage
> > > patterns of synchronization in multi-threaded applications, which,
> > > while not too difficult for the easier primitives like events, mutexes,
> > > and semaphores,...becomes a bit harder when you try to make a "thread
> > > class".  Many programmers have tried to make "thread classes" only to
> > > find that there is a severe penalty for choosing a wrong conceptual
> > > model.
>
> > What kind of penalty? Performance or constrained design possibilities?
>
> Probably both.
>
> > > I fell into this trap.  The best advice I can give in this
> > > regard is to say that the concept of the thread itself should not be
> > > modeled as a class.
>
> > That's exactly how I did it years ago. That's probably where I'd start
> > from again if/when I dust off and revive that code. I was probably
> > influenced by the Borland class library and maybe even MFC. So
> > you think they got it wrong huh?
>
> There are two philosophies: a thread is an asynchronous
> function, or a thread is a class.  The Boost model tries for a
> sort of compromize between the two: a thread is a class, but one
> that acts like an implicitly called functional object, and whose
> lifetime doesn't need to extend to the lifetime of the entire
> thread.

Some kind of "thread launcher"?

> In my own work, I distinguish between joinable threads and those
> that you "fire and forget".  Joinable threads are a class, so
> you have something to join with; detached threads are started by
> a simple function call.
>
> Another philosophy involves "futures": basically, it consists of
> a function to start the thread; the function returns an object
> which can later be used for joins.

OK. I don't have knowledge of the entire range of design problems that
threads can solve, so now I'm wondering about those other ones that I
haven't worked with yet. For instance, I don't know the concept
"joinable threads". Besides that though, do you think that Le Chaud
Lapin was talking about detachable threads when he stated that modeling
threads as classes was a bad idea?

John


--
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
JQP
1/13/2007 11:59:29 AM
"Le Chaud Lapin" <jaibuduvin@gmail.com> wrote in message
news:1168582546.890622.50020@a75g2000cwd.googlegroups.com...

[snip]

OK, but I was expecting insight as to why you thought modeling threads as
objects is wrong, and then you proceded to explain that you indeed did model
threads as objects via a class that calls CreateThread in the
constructor and CloseHandle in the destructor. You said:

"Many programmers have tried to make "thread classes" only to find that
there is a severe penalty for choosing a wrong conceptual model.  I fell
into this trap.  The best advice I can give in this regard is to say that
the concept of the thread itself should not bemodeled as a class."

Looks like a contradiction to me.

John


--
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
JohnQ
1/13/2007 12:01:51 PM
JohnQ wrote:
> "Peter Dimov" <pdimov@gmail.com> wrote in message
> news:1168567134.727505.269630@v45g2000cwv.googlegroups.com...
> > JQP wrote:
> >> Carlos Moreno wrote:
> >> > JohnQ wrote:
> >> >
> >> > > Why have more threads than the number of processor cores?
> >> >
> >> > I'm baffled by this question ...
> >> >
> >> > The above question is exactly equivalent to "why would we want
> >> > multithreading?"
> >>
> >> Not at all. I was just wondering why/when that "rule" should be
> >> used. Is it whenever you want two or more tasks to APPEAR to
> >> be running at the same time rather wanting to get the most
> >> work done per core? For example: GUI prog, use as many as
> >> your heart desires; Database server: limit to the number of cores.
> >
> > Pretty much, except that you want the number of _running_ threads to be
> > (approximately) equal to the number of cores.
>
> That's all that CAN run (#of RUNNING threads = # of cores). Limiting the
> number of ACTIVE threads to the number of cores should increase efficiency
> by eliminating thread switching. Probably what you meant (?).

My bad, "running" already has an established meaning. So yes, I meant
the number of "runnable" threads in Java terminology, or the number of
threads that are either "running" or "ready" in non-Java terminology.
It's clear from your other posts that you understood what I meant
despite my sloppy wording. :-) The gist of it is that if you expect 40%
of your threads to be blocked at any given moment, you need to spawn
(1.7 * cores) threads (kernel-provided thread pools can do better since
they know which threads are blocked).


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Peter
1/13/2007 9:00:50 PM
{ This subthread about whether time-slicing is good for DB servers is 
not only heading off-topic, but is already there.  I'm approving this as 
a follow-up, because it would be unreasonable to stop a thread with no 
warning.  Please return to issues more on-topic for cl++m. -mod/aps }

JohnQ wrote:

>>>[...] For example: GUI prog, use as many as
>>>your heart desires; Database server: limit to the number of cores.
>>
>>Why the principle applied to DB servers??
> 
> [...] In light of that, I'll say that there
> is no need to give the appearance of multiple DB transactions proceeding
> along concurrently akin to indeed giving an analogous impression with GUIs.

You don't need to give *the impression* of multiple DB transactions
running concurrently --- multiple DB transactions *are* running
concurrently (as a general rule for a DB server --- maybe not at a
particular point in time)

> I think the answer to your question is: because the goal is to get the most
> work done in the least amount of time (maximize processing efficiency) and
> that means minimizing the processing overhead (thread switching).

This argument is applicable to CPU-intensive tasks;  more specifically,
to tasks that are *exclusievly* (or almost exclusively) CPU intensive.

My guesstimate is that the tasks on a DB server are more IO-bound than
CPU-bound  (well, or maybe close to half-and-half, as there certainly
are bursts of CPU-intensive processing to deal with query planning,
compiling, optimization, indexing, etc.).

If the task is IO-bound, then definitely multi-tasking by time slicing
*will improve* the overall performance  (notice how I now write multi-
tasking --- whether or not the DB server implements it as multithreading
or multiple processes, that's not obvious to me;  but my argument
stands;  the principle of limiting the number of active threads to
the number of CPU cores is not applicable to a DB server, since DB
servers should definitely benefit from time slicing, giving its
IO-bound (or partly IO-bound) nature.

> But it shouldn't be disk bound. 

The way I understand it, it has no choice but to be disk-bound;
for DB-writes, there's no way around;  for read, there's certainly
caching, etc. --- but that would be only if there are multiple
frequent readings of the same data;  then disk reading would go
almost down to zero.

> performing storage subsystem. The goal is to service all requests in a
> reasonable amount of time and avoid the following:
> 
> "Because of the high transaction volume we are encountering at this time,
> your request could not be serviced. 

This is DB configuration parameters, and not software design or
implementation issues.

>>I would definitely expect a DB server --- if taking advantage of
>>multithreading at all --- to have more running threads than the
>>available cores.
> 
> Well in the scenario where the threads are in-progress transactions (not
> long running ones)

Why would you assume that this is the case??  This is definitely
not what I had in mind when I suggested my point of view.

Carlos
--

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Carlos
1/13/2007 9:09:24 PM
JohnQ wrote:
> "Carlos Moreno" <moreno_at_mochima_dot_com@mailinator.com> wrote in message
> news:l2Vph.80252$9i3.367737@wagner.videotron.net...
> > JQP wrote:

> >> [...] For example: GUI prog, use as many as
> >> your heart desires; Database server: limit to the number of cores.

> > Why the principle applied to DB servers??

> Someone emphasized the point that I should have said "limit the number of
> RUNNING threads to the number of cores". As I think about that now, I
> realize that it's impossible to have more threads running than the number of
> cores (!). So, I think he meant that the number of ACTIVE threads (the ones
> timeslicing the CPU) should be limited to the number of cores so as not to
> incur the thread switching overhead. In light of that, I'll say that there
> is no need to give the appearance of multiple DB transactions proceeding
> along concurrently akin to indeed giving an analogous impression with GUIs.

> I think the answer to your question is: because the goal is to get the most
> work done in the least amount of time (maximize processing efficiency) and
> that means minimizing the processing overhead (thread switching).

That's the goal for some uses of multi-threading, but it's
certainly not the only goal for data bases.  A data base has to
be responsive---even if one client makes an expensive request
(in terms of CPU), the data base must respond rapidly to simple
requests from other clients.

Responsiveness is one of the most frequent reasons for using
multithreading.  Responsiveness of a GUI, or responisiveness of
a server.  (Data bases are just an example of a server.)

> > True that there is some
> > intensive work to be done, but I would expect that a portion of the
> > processing would be IO-bound  (yes, DB servers should optimize as
> > much as possible the access to be made from memory instead of from
> > disk, but it can't be 100% diskless).

> But it shouldn't be disk bound.

Part of it has to be, if you want to guarantee transactional
integrity.

> That may mean you probably need a higher
> performing storage subsystem. The goal is to service all requests in a
> reasonable amount of time and avoid the following:

> "Because of the high transaction volume we are encountering at this time,
> your request could not be serviced. Please try again later. We regret any
> and all inconvenience this may have caused and you should indeed demand
> credit for the time the service was unavailable to you."

Exactly.  And that means that my simple request must be able to
interrupt a long running complex request.

> Saturating the disk subsystem is an exception (error) that must be handled
> somehow (perhaps like above).

It's not a question of saturation.  It's a question of letting
other requests advance while my request is blocked for disk
access.  And any request which modifies data will block.  (And
again, there's nothing special about data bases here.  This is
true for just about any server.)

      [...]
> > I would definitely expect a DB server --- if taking advantage of
> > multithreading at all --- to have more running threads than the
> > available cores.

> Well in the scenario where the threads are in-progress transactions (not
> long running ones), why would you want to switch between them and make small
> progress toward completion of a bunch of them rather than taking a 1000 foot
> view and seeing that more transactions are completed over the same period
> time if the wasted CPU time used for switching threads is eliminated?

If all of the requests require a lot of CPU time, one could ask
the question.  Typically, however, if I send a select request
over a single table, with a where clause based on the primary
index, I don't expect it to take minutes, just because someone
else is doing a complicated join over a number of tables, using
unindexed columns.

--
James Kanze (Gabi Software)            email: james.kanze@gmail.com
Conseils en informatique orient�e objet/
                    Beratung in objektorientierter Datenverarbeitung
9 place S�mard, 78210 St.-Cyr-l'�cole, France, +33 (0)1 30 23 00 34


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
James
1/14/2007 6:49:41 PM
Le Chaud Lapin wrote:
> JQP wrote:
> > Le Chaud Lapin wrote:
> > > I never
> > > thought I would say it, but the thought of not having bona-fide threads
> > > is frightening.
> > And by that you mean on any other platform or that either Windows or
> > UNIX is lacking them? By "bona-fide" threads, do you mean real threads
> > rather than something like pthreads?

> Yes and yes.

Why are pthreads not "bona-fide" threads?  At the threading
level, they are almost indistiguishable (to the process) from
windows threads.  About the only difference is that they offer a
larger variety of synchronization methods.

> My system model will fall apart on an OS that does not
> have threads.  For example, I remember trying to choose between Windows
> CE and PalmOs for a "small device" test system.  When I saw that Palm
> OS did not have multi-tasking, the answer was easy.  They do have
> Cobalt now, but to not have had it before says something about the OS.
> Also, for a while, creating threads in Unix was not as simple as doing
> a CreateThread.  The newer models like LWP seem to have helped a lot.

What does CreateThread do that pthread_create doesn't?  (And I'm
not sure what you mean with regards to LWP.  Depending on who's
using the term, LWP is either a synonym for threads, or an
implementation technique invisible to the user.)

      [...]
> > Well that could be put into a thread class (orderly shutdown). Indeed
> > that would be a reason to wrap the platform abstraction. But yes, other
> > threading things like locks are the obvious ones to wrap up (one of
> > mine is called AutoLock which wraps a mutex).

> Yep.  My thread class includes as part of its design a mechanism for
> orderly shutdown.  I would not be surprised if the code is the same.

Interesting.  Orderly shutdown is one of the things I've not
found in Windows threads.  TerminateThread is not an equivalent
of pthread_cancel.

Note that orderly shutdown requires collaboration from the
thread.  I'm not sure that it will make it into the standard; in
fact, I rather doubt it will, precisely because there is no
accepted standard way of achieving it.

> > > might be nice to wait for a thread to die.  It might be nice to wait
> > > for an event, three mutexes, a semaphore, and 2 threads to die, or any
> > > one of these things to be signaled, etc.    I was able to make all
> > > classes RAII, Yin/Yang style (mutexes, etc) except the thread class.

> > And the reason you couldn't make an RAII-style thread class is....?

> Honestly, I cannot remember.

The reason seems obvious, at least for a joinable thread.  The
lifetime of the thread is independant of any scope in the
function which creates it.

--
James Kanze (Gabi Software)            email: james.kanze@gmail.com
Conseils en informatique orient�e objet/
                    Beratung in objektorientierter Datenverarbeitung
9 place S�mard, 78210 St.-Cyr-l'�cole, France, +33 (0)1 30 23 00 34


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
James
1/14/2007 6:59:26 PM
JQP wrote:
> James Kanze wrote:
> > JohnQ wrote:
> > > "Le Chaud Lapin" <jaibuduvin@gmail.com> wrote :

      [...]
> > There are two philosophies: a thread is an asynchronous
> > function, or a thread is a class.  The Boost model tries for a
> > sort of compromize between the two: a thread is a class, but one
> > that acts like an implicitly called functional object, and whose
> > lifetime doesn't need to extend to the lifetime of the entire
> > thread.

> Some kind of "thread launcher"?

Not really, either.  The problem is that the Boost model tries
to use a single class for several very different things:
identifying the thread, starting it and as a future.  When used
to start a detached thread, it is a thread launcher.  If you
don't detach, it is the classical thread object, to which you
can join.  And you can have objects of type thread which are
copies, or are created independantly, which only serve to
identify a thread.

My experience suggests that you don't need a class to represent
a detached thread; a global function corresponds better to what
you are doing.

> > In my own work, I distinguish between joinable threads and those
> > that you "fire and forget".  Joinable threads are a class, so
> > you have something to join with; detached threads are started by
> > a simple function call.

> > Another philosophy involves "futures": basically, it consists of
> > a function to start the thread; the function returns an object
> > which can later be used for joins.

> OK. I don't have knowledge of the entire range of design problems that
> threads can solve, so now I'm wondering about those other ones that I
> haven't worked with yet. For instance, I don't know the concept
> "joinable threads".

Anytime you want to use the response from a thread, you need a
joinable thread.  It's also very hard to do a clean shutdown
without them.

> Besides that though, do you think that Le Chaud
> Lapin was talking about detachable threads when he stated that modeling
> threads as classes was a bad idea?

Maybe.  It's hard to say what he was thinking about; I have no
idea what type of application he works on (except that it must
be very different from mine, since he seems to be able to easily
force the lifetime of everything to correspond to a scope).

--
James Kanze (Gabi Software)            email: james.kanze@gmail.com
Conseils en informatique orient�e objet/
                    Beratung in objektorientierter Datenverarbeitung
9 place S�mard, 78210 St.-Cyr-l'�cole, France, +33 (0)1 30 23 00 34


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
James
1/14/2007 7:00:01 PM
James Kanze wrote:
> But it [WaitForMultipleObjects] is so simple to emulate.  Just start a thread for each
> thing you want to wait for, which posts a message in a queue
> when that event arrives, and wait on the queue in the main
> thread.  (But I agree that it is nice for the system to do it
> for you.)

How do you stop the waiter threads when you need the resources they're
waiting on? E.g. if you have a thread waiting on a socket read, how do
you stop it so you can do a write on the same socket? And how do you
stop it to do an orderly shutdown?

Yechezkel Mett

--
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Yechezkel
1/15/2007 8:57:18 AM
"James Kanze" <james.kanze@gmail.com> wrote in message 
news:1168779751.471598.149810@a75g2000cwd.googlegroups.com...
> Le Chaud Lapin wrote:
>> JQP wrote:
>> > Le Chaud Lapin wrote:
>> > Well that could be put into a thread class (orderly shutdown). Indeed
>> > that would be a reason to wrap the platform abstraction. But yes, other
>> > threading things like locks are the obvious ones to wrap up (one of
>> > mine is called AutoLock which wraps a mutex).
>
>> Yep.  My thread class includes as part of its design a mechanism for
>> orderly shutdown.  I would not be surprised if the code is the same.
>
> Interesting.  Orderly shutdown is one of the things I've not
> found in Windows threads.  TerminateThread is not an equivalent
> of pthread_cancel.

No one said TerminateThread was being used for "orderly shutdown". Obviously

it is "violent" termination of a thread.

> Note that orderly shutdown requires collaboration from the
> thread.

Yes, some kind of "unblocking function" for blocking threads or a flag for 
looping threads or...

>  I'm not sure that it will make it into the standard; in
> fact, I rather doubt it will, precisely because there is no
> accepted standard way of achieving it.

Well not in every case, but in certain scenarios there are. But at that high

level, maybe the standard does not belong anyway because it's getting to far

into the application-specific design and "personal preference" category.

John 


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
JohnQ
1/15/2007 4:35:15 PM
"James Kanze" <james.kanze@gmail.com> wrote in message 
news:1168778431.817385.276300@11g2000cwr.googlegroups.com...
> JohnQ wrote:
>> "Carlos Moreno" <moreno_at_mochima_dot_com@mailinator.com> wrote in 
>> message
>> news:l2Vph.80252$9i3.367737@wagner.videotron.net...
>> > JQP wrote:
>
>> >> [...] For example: GUI prog, use as many as
>> >> your heart desires; Database server: limit to the number of cores.
>
>> > Why the principle applied to DB servers??
>
>> Someone emphasized the point that I should have said "limit the number of
>> RUNNING threads to the number of cores". As I think about that now, I
>> realize that it's impossible to have more threads running than the number

>> of
>> cores (!). So, I think he meant that the number of ACTIVE threads (the 
>> ones
>> timeslicing the CPU) should be limited to the number of cores so as not 
>> to
>> incur the thread switching overhead. In light of that, I'll say that 
>> there
>> is no need to give the appearance of multiple DB transactions proceeding
>> along concurrently akin to indeed giving an analogous impression with 
>> GUIs.
>
>> I think the answer to your question is: because the goal is to get the 
>> most
>> work done in the least amount of time (maximize processing efficiency) 
>> and
>> that means minimizing the processing overhead (thread switching).
>
> That's the goal for some uses of multi-threading, but it's
> certainly not the only goal for data bases.  A data base has to
> be responsive---even if one client makes an expensive request
> (in terms of CPU), the data base must respond rapidly to simple
> requests from other clients.
>
> Responsiveness is one of the most frequent reasons for using
> multithreading.  Responsiveness of a GUI, or responisiveness of
> a server.  (Data bases are just an example of a server.)

It's a matter of degree. You'll probably not tolerate the loss of efficiency

in a DB server like you would in a GUI just to get the APPEARANCE of 
concurrency.

>> > True that there is some
>> > intensive work to be done, but I would expect that a portion of the
>> > processing would be IO-bound  (yes, DB servers should optimize as
>> > much as possible the access to be made from memory instead of from
>> > disk, but it can't be 100% diskless).
>
>> But it shouldn't be disk bound.
>
> Part of it has to be, if you want to guarantee transactional
> integrity.

By "disk bound" I meant "saturating the disk to the throughput limit of the 
storage subsystem" and not simply "writing the log entries to disk before 
transaction commit". The disk subsystem should be designed/chosen/specified 
etc. to be able to meet the application requirements (the expected 
transaction load and the tolerable amount of user inconvenience at peak load

times).

>> That may mean you probably need a higher
>> performing storage subsystem. The goal is to service all requests in a
>> reasonable amount of time and avoid the following:
>
>> "Because of the high transaction volume we are encountering at this time,
>> your request could not be serviced. Please try again later. We regret any
>> and all inconvenience this may have caused and you should indeed demand
>> credit for the time the service was unavailable to you."
>
> Exactly.  And that means that my simple request must be able to
> interrupt a long running complex request.

Well you're assuming some transaction is hogging the CPU and my scenario has

always been the one where the disk IO is at saturation level. Different 
scenarios.

>> Saturating the disk subsystem is an exception (error) that must be 
>> handled
>> somehow (perhaps like above).
>
> It's not a question of saturation.

Sure it is (in the scenario that I put forth).

> It's a question of letting
> other requests advance while my request is blocked for disk
> access.

Now you're making assumptions that that is possible. Sure if possible go do 
something else. In another post, I suggested that "limiting the number of 
threads to the number of CPU cores" is actually used to mean that or "there 
abouts", the key being not to let so many threads be active that high 
transaction volumes unnecessarily engage in a lot of thread switching. The 
scenario was meant simply to emphasize when/where the 
limit-threads-to-number-of-cores "rule" applies.
Chances are that things are going to start piling up behind the inadequate 
IO until something else gives (either because the system was inadequate to 
begin with, or the usage patterns changed unexpectedly or that was 
considered tolerable).

> And any request which modifies data will block.

Say, 2 cores, 2 transactions active, one blocks the other for the same data.

Then it's a design decision as to what degree you will allow other 
transactions to startup with the thought that maybe they won't block and can

proceed while the other one waits. The one-thread-per-core "rule" will 
probably deter you from creating large thread pools because otherwise under 
non-blocking conditions there will be more thread switching than necessary. 
(Or at least that's how my thinking is proceeding at this time!).

OTOH, if the disks are already glowing red hot with activity because the 
transaction volume exceeds the disk capabilities, that's another story (but 
is the original scenario put forth). In that case, spawning new transaction 
threads isn't going to help matters. They will just start piling up if they 
aren't limited somehow. How much queueing of transactions (suspended 
threads) is built in to DB server software is a design/engineering issue but

not one related to the "how many threads per core" issue.

> (And
> again, there's nothing special about data bases here.  This is
> true for just about any server.)
>
>      [...]
>> > I would definitely expect a DB server --- if taking advantage of
>> > multithreading at all --- to have more running threads than the
>> > available cores.
>
>> Well in the scenario where the threads are in-progress transactions (not
>> long running ones), why would you want to switch between them and make 
>> small
>> progress toward completion of a bunch of them rather than taking a 1000 
>> foot
>> view and seeing that more transactions are completed over the same period
>> time if the wasted CPU time used for switching threads is eliminated?
>
> If all of the requests require a lot of CPU time, one could ask
> the question.  Typically, however, if I send a select request
> over a single table, with a where clause based on the primary
> index, I don't expect it to take minutes, just because someone
> else is doing a complicated join over a number of tables, using
> unindexed columns.

Analytical databases where not the scenario though. OLTP was. Yes, a lot of 
database software today can do it all, but that was not the scenario brought

forth to give context for discussing the one-thread-per-core "rule", where 
it applies, where it doesn't apply and to what degree it applies (and 
potentially the applicability of other threading strategies).

In a GUI, it's nice to see multiple windows make drawing progress at the 
same time. In an OLTP DB, it's all or nothing so intermediary progress 
monitoring is not required and therefore thread switching is unnecessary and

undesireable. If you build a DB server with the same thread pooling strategy

as the GUI, it's not going to be as efficient as it could be. The DB server 
will probably be built close to the one-thread-per-core strategy while the 
GUI will be built with a many-threads-per-core strategy.

John 


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
JohnQ
1/15/2007 4:36:37 PM
"James Kanze" <james.kanze@gmail.com> wrote in message 
news:1168780230.381634.41480@11g2000cwr.googlegroups.com...
> JQP wrote:
>> James Kanze wrote:
>> > JohnQ wrote:
>> > > "Le Chaud Lapin" <jaibuduvin@gmail.com> wrote :
>
>      [...]
>> > There are two philosophies: a thread is an asynchronous
>> > function, or a thread is a class.  The Boost model tries for a
>> > sort of compromize between the two: a thread is a class, but one
>> > that acts like an implicitly called functional object, and whose
>> > lifetime doesn't need to extend to the lifetime of the entire
>> > thread.
>
>> Some kind of "thread launcher"?
>
> Not really, either.  The problem is that the Boost model tries
> to use a single class for several very different things:
> identifying the thread, starting it and as a future.  When used
> to start a detached thread, it is a thread launcher.  If you
> don't detach, it is the classical thread object, to which you
> can join.  And you can have objects of type thread which are
> copies, or are created independantly, which only serve to
> identify a thread.
>
> My experience suggests that you don't need a class to represent
> a detached thread; a global function corresponds better to what
> you are doing.
>
>> > In my own work, I distinguish between joinable threads and those
>> > that you "fire and forget".  Joinable threads are a class, so
>> > you have something to join with; detached threads are started by
>> > a simple function call.
>
>> > Another philosophy involves "futures": basically, it consists of
>> > a function to start the thread; the function returns an object
>> > which can later be used for joins.
>
>> OK. I don't have knowledge of the entire range of design problems that
>> threads can solve, so now I'm wondering about those other ones that I
>> haven't worked with yet. For instance, I don't know the concept
>> "joinable threads".
>
> Anytime you want to use the response from a thread, you need a
> joinable thread.  It's also very hard to do a clean shutdown
> without them.

OK "joinable" is semantically foreign to me. If you would have said 
'waitable thread', I would have groked it right away. Example of a 
"joinable"/"waitable" thread: an intermediate result of some complex 
mathematical formula. Example of a "detached" thread: worker threads in a 
thread pool handling incoming database transactions. Yes?

In Windows, one does not have to specify anything to get a "joinable" 
thread: one just waits for the thread handle to become signaled. (That is, 
if the concept of "waiting on" and "joining" is the same).

Why is it hard to cleanly shutdown a detached thread? On the flip side, why 
is it easy to cleanly shutdown a joinable thread? Oh, did you mean shutdown 
the application rather than the threads (which becomes the problem of 
shutting down the threads)?

>> Besides that though, do you think that Le Chaud
>> Lapin was talking about detachable threads when he stated that modeling
>> threads as classes was a bad idea?
>
> Maybe.  It's hard to say what he was thinking about; I have no
> idea what type of application he works on (except that it must
> be very different from mine, since he seems to be able to easily
> force the lifetime of everything to correspond to a scope).

John 


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
JohnQ
1/15/2007 4:37:39 PM
JohnQ wrote:
> "James Kanze" <james.kanze@gmail.com> wrote in message
> news:1168780230.381634.41480@11g2000cwr.googlegroups.com...
> > JQP wrote:

      [...]
> >> OK. I don't have knowledge of the entire range of design problems that
> >> threads can solve, so now I'm wondering about those other ones that I
> >> haven't worked with yet. For instance, I don't know the concept
> >> "joinable threads".

> > Anytime you want to use the response from a thread, you need a
> > joinable thread.  It's also very hard to do a clean shutdown
> > without them.

> OK "joinable" is semantically foreign to me.

It's the standard vocabulary.  It's the term used in all of the
threading interfaces I know: Posix, Boost, Java...  I'd expect
the term to be familiar with anyone familiar with threading.

> If you would have said
> 'waitable thread', I would have groked it right away. Example of a
> "joinable"/"waitable" thread: an intermediate result of some complex
> mathematical formula. Example of a "detached" thread: worker threads in a
> thread pool handling incoming database transactions. Yes?

It depends.  A lot of server software will use joinable threads
in order to ensure a clean shutdown.  It's especially true if
you use objects for threads.  GUI worker threads will typically
be detached, since the GUI event thread cannot very well do a
join, although some designs will use a special reaper thread to
do the joins.  (Again, this is done in order to ensure clean
shutdown.)  (I'm not sure, but I have the impression that you
can close the thread handle without stopping the thread.  This
corresponds very exactly to detaching the thread; the vocabulary
is a little wierd, but in this case, perhaps justifiably so,
because of the unified way Windows handles handles.)

Note that similar issues concern processes.

> In Windows, one does not have to specify anything to get a "joinable"
> thread: one just waits for the thread handle to become signaled. (That is,
> if the concept of "waiting on" and "joining" is the same).

And if no one ever waits for the thread?  A thread uses system
resources, and in a joinable thread, those resources must be
kept by the system until the join has taken place.  If a thread
is detached, on the other hand, the system frees up the
resources as soon as the thread has finished.

> Why is it hard to cleanly shutdown a detached thread?

Because you don't know when it has finished.  (And of course,
you can't call exit() safely until it has finished.)

> On the flip side, why is it easy to cleanly shutdown a
> joinable thread?  Oh, did you mean shutdown the application
> rather than the threads (which becomes the problem of shutting
> down the threads)?

Shutdown means shutting down the application, yes.  With the
constraint that you cannot call exit as long as any threads are
running.

--
James Kanze (GABI Software)             email:james.kanze@gmail.com
Conseils en informatique orient�e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S�mard, 78210 St.-Cyr-l'�cole, France, +33 (0)1 30 23 00 34


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
James
1/15/2007 11:13:09 PM
JohnQ wrote:
> "James Kanze" <james.kanze@gmail.com> wrote in message
> news:1168778431.817385.276300@11g2000cwr.googlegroups.com...
> > JohnQ wrote:

> >> I think the answer to your question is: because the goal is to get the
> >> most
> >> work done in the least amount of time (maximize processing efficiency)
> >> and
> >> that means minimizing the processing overhead (thread switching).

> > That's the goal for some uses of multi-threading, but it's
> > certainly not the only goal for data bases.  A data base has to
> > be responsive---even if one client makes an expensive request
> > (in terms of CPU), the data base must respond rapidly to simple
> > requests from other clients.

> > Responsiveness is one of the most frequent reasons for using
> > multithreading.  Responsiveness of a GUI, or responisiveness of
> > a server.  (Data bases are just an example of a server.)

> It's a matter of degree. You'll probably not tolerate the loss of efficiency
> in a DB server like you would in a GUI just to get the APPEARANCE of
> concurrency.

It depends on the application.  You generally will not tolerate
the loss of responsivity just because one or two clients are
performing extremely complex requests.

> >> > True that there is some
> >> > intensive work to be done, but I would expect that a portion of the
> >> > processing would be IO-bound  (yes, DB servers should optimize as
> >> > much as possible the access to be made from memory instead of from
> >> > disk, but it can't be 100% diskless).

> >> But it shouldn't be disk bound.

> > Part of it has to be, if you want to guarantee transactional
> > integrity.

> By "disk bound" I meant "saturating the disk to the throughput limit of the
> storage subsystem"

That's not what disk bound means.  Disk bound means that
speeding up the CPU processing won't improve the apparent
throughput.

      [...]
> > It's a question of letting
> > other requests advance while my request is blocked for disk
> > access.

> Now you're making assumptions that that is possible.

Not assumptions.  Facts, based on experience.  It's a pretty
poor data base if one access blocks all of the others.

      [...]
> > And any request which modifies data will block.

> Say, 2 cores, 2 transactions active, one blocks the other for the same data.

It's pretty rare in my applications for everyone to be accessing
the exact same records.  I suspect that this is pretty general.

> Then it's a design decision as to what degree you will allow other
> transactions to startup with the thought that maybe they won't block and can
> proceed while the other one waits. The one-thread-per-core "rule" will
> probably deter you from creating large thread pools because otherwise under
> non-blocking conditions there will be more thread switching than necessary.
> (Or at least that's how my thinking is proceeding at this time!).

You're thinking doesn't correspond to how the larger data bases
are organized.  You might want to check into the documentation
of Oracle---the explain pretty well how their data base is
organized (and there are a lot more processes than processors).

--
James Kanze (GABI Software)             email:james.kanze@gmail.com
Conseils en informatique orient�e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S�mard, 78210 St.-Cyr-l'�cole, France, +33 (0)1 30 23 00 34


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
James
1/16/2007 12:25:28 AM
JohnQ wrote:
> "James Kanze" <james.kanze@gmail.com> wrote in message
> news:1168779751.471598.149810@a75g2000cwd.googlegroups.com...
> > Le Chaud Lapin wrote:
> >> JQP wrote:
> >> > Le Chaud Lapin wrote:
> >> > Well that could be put into a thread class (orderly shutdown). Indeed
> >> > that would be a reason to wrap the platform abstraction. But yes, other
> >> > threading things like locks are the obvious ones to wrap up (one of
> >> > mine is called AutoLock which wraps a mutex).

> >> Yep.  My thread class includes as part of its design a mechanism for
> >> orderly shutdown.  I would not be surprised if the code is the same.

> > Interesting.  Orderly shutdown is one of the things I've not
> > found in Windows threads.  TerminateThread is not an equivalent
> > of pthread_cancel.

> No one said TerminateThread was being used for "orderly shutdown". Obviously
> it is "violent" termination of a thread.

I know.  That's what the documentation says.  So what do you
use?  I couldn't find anything like pthread_cancel in the
Microsoft documentation.

> > Note that orderly shutdown requires collaboration from the
> > thread.

> Yes, some kind of "unblocking function" for blocking threads or a flag for
> looping threads or...

> >  I'm not sure that it will make it into the standard; in
> > fact, I rather doubt it will, precisely because there is no
> > accepted standard way of achieving it.

> Well not in every case, but in certain scenarios there are.

In individual cases, it's generally possible to provide an
application specific solution.  Which involves using time-outs
and such, because there is no clean way of interrupting a
blocked thread.

> But at that high
> level, maybe the standard does not belong anyway because it's getting to far
> into the application-specific design and "personal preference" category.

At the lowest level, it would be nice to have a standard
function to "unblock" the thread, so that you don't need
timeouts and polling.

--
James Kanze (GABI Software)             email:james.kanze@gmail.com
Conseils en informatique orient�e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S�mard, 78210 St.-Cyr-l'�cole, France, +33 (0)1 30 23 00 34


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
James
1/16/2007 12:26:12 AM
"James Kanze" <james.kanze@gmail.com> wrote in message
news:1168885159.033449.42330@51g2000cwl.googlegroups.com...
> JohnQ wrote:
>> "James Kanze" <james.kanze@gmail.com> wrote in message
>> news:1168779751.471598.149810@a75g2000cwd.googlegroups.com...
>> > Le Chaud Lapin wrote:
>> >> JQP wrote:
>> >> > Le Chaud Lapin wrote:
>> >> > Well that could be put into a thread class (orderly shutdown). 
>> >> > Indeed
>> >> > that would be a reason to wrap the platform abstraction. But yes, 
>> >> > other
>> >> > threading things like locks are the obvious ones to wrap up (one of
>> >> > mine is called AutoLock which wraps a mutex).
>
>> >> Yep.  My thread class includes as part of its design a mechanism for
>> >> orderly shutdown.  I would not be surprised if the code is the same.
>
>> > Interesting.  Orderly shutdown is one of the things I've not
>> > found in Windows threads.  TerminateThread is not an equivalent
>> > of pthread_cancel.
>
>> No one said TerminateThread was being used for "orderly shutdown". 
>> Obviously
>> it is "violent" termination of a thread.
>
> I know.  That's what the documentation says.  So what do you
> use?  I couldn't find anything like pthread_cancel in the
> Microsoft documentation.

I haven't revived my old thread wrappers yet, but I put an unblocking
function (virtual) int the Thread class that would cause the thread to exit.
How to "unblock" or stop looping in in a thread is something for the derived
application-specific thread class to determine. That said, did you look at
the ExitThread API? I view ExitThread as a last resort API similar to
TerminateThread. I think they do the same things except ExitThread cleans up
some resources held by the thread. So, I prefer designing-in an "exit
strategy". I'm not sure what percentage of the time this is possible though.

>
>> > Note that orderly shutdown requires collaboration from the
>> > thread.
>
>> Yes, some kind of "unblocking function" for blocking threads or a flag 
>> for
>> looping threads or...
>
>> >  I'm not sure that it will make it into the standard; in
>> > fact, I rather doubt it will, precisely because there is no
>> > accepted standard way of achieving it.
>
>> Well not in every case, but in certain scenarios there are.
>
> In individual cases, it's generally possible to provide an
> application specific solution.  Which involves using time-outs
> and such, because there is no clean way of interrupting a
> blocked thread.

In general you mean (no general way of interrupting a blocked thread. I'm OK
with that.). I wouldn't consider time-outs as a general strategy though at
all, but for specific cases maybe (hmm.. I'm thinking they address a
different issue). The thing with time-outs of course is that sometimes with
a long time-out you would want to cancel that thread and then you have the
same problem as before.

>> But at that high
>> level, maybe the standard does not belong anyway because it's getting to 
>> far
>> into the application-specific design and "personal preference" category.
>
> At the lowest level, it would be nice to have a standard
> function to "unblock" the thread, so that you don't need
> timeouts and polling.

I don't have 100 examples to draw upon to make a general empirical
statement, but I do think that maybe neither timeouts or polling address the
issue. I'm not sure how you meant polling either. If you meant
setting/checking a flag on each iteration for a looping non-blocking thread,
than I'd say that is adequate solution for graceful thread exit.

John


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
JohnQ
1/16/2007 9:30:26 AM
"James Kanze" <james.kanze@gmail.com> wrote in message
news:1168884935.734893.276590@m58g2000cwm.googlegroups.com...
> JohnQ wrote:
>> "James Kanze" <james.kanze@gmail.com> wrote in message
>> news:1168778431.817385.276300@11g2000cwr.googlegroups.com...
>> > JohnQ wrote:
>
>> >> I think the answer to your question is: because the goal is to get the
>> >> most
>> >> work done in the least amount of time (maximize processing efficiency)
>> >> and
>> >> that means minimizing the processing overhead (thread switching).
>
>> > That's the goal for some uses of multi-threading, but it's
>> > certainly not the only goal for data bases.  A data base has to
>> > be responsive---even if one client makes an expensive request
>> > (in terms of CPU), the data base must respond rapidly to simple
>> > requests from other clients.
>
>> > Responsiveness is one of the most frequent reasons for using
>> > multithreading.  Responsiveness of a GUI, or responisiveness of
>> > a server.  (Data bases are just an example of a server.)
>
>> It's a matter of degree. You'll probably not tolerate the loss of 
>> efficiency
>> in a DB server like you would in a GUI just to get the APPEARANCE of
>> concurrency.
>
> It depends on the application.  You generally will not tolerate
> the loss of responsivity just because one or two clients are
> performing extremely complex requests.

OK, you're thinking SQL server and I'm thinking OLTP server.

>> >> > True that there is some
>> >> > intensive work to be done, but I would expect that a portion of the
>> >> > processing would be IO-bound  (yes, DB servers should optimize as
>> >> > much as possible the access to be made from memory instead of from
>> >> > disk, but it can't be 100% diskless).
>
>> >> But it shouldn't be disk bound.
>
>> > Part of it has to be, if you want to guarantee transactional
>> > integrity.
>
>> By "disk bound" I meant "saturating the disk to the throughput limit of 
>> the
>> storage subsystem"
>
> That's not what disk bound means.  Disk bound means that
> speeding up the CPU processing won't improve the apparent
> throughput.

I see no difference in meaning.

>      [...]
>> > It's a question of letting
>> > other requests advance while my request is blocked for disk
>> > access.
>
>> Now you're making assumptions that that is possible.
>
> Not assumptions.  Facts, based on experience.  It's a pretty
> poor data base if one access blocks all of the others.

The assumption you are making is of a specific scenario/implementation.
Somehow you are going to bound the number of active threads when you want to
maximize efficiency is what I'm saying. The amount of "disk not available at
this time" that an application can tolerate is limited and must be designed
for, but it's not the problem being discussed I think: the focus is
when/why/if/to-what-degree the one-thread-per-core "rule" applies. I think
you have to analyze that first outside of exceptional conditions.

>      [...]
>> > And any request which modifies data will block.
>
>> Say, 2 cores, 2 transactions active, one blocks the other for the same 
>> data.
>
> It's pretty rare in my applications for everyone to be accessing
> the exact same records.  I suspect that this is pretty general.

It's a simplisticly contrived example to aid in analyzing the
one-thread-per-core "rule" without bring more into the discussion than
necessary.

>> Then it's a design decision as to what degree you will allow other
>> transactions to startup with the thought that maybe they won't block and 
>> can
>> proceed while the other one waits. The one-thread-per-core "rule" will
>> probably deter you from creating large thread pools because otherwise 
>> under
>> non-blocking conditions there will be more thread switching than 
>> necessary.
>> (Or at least that's how my thinking is proceeding at this time!).
>
> You're thinking doesn't correspond to how the larger data bases
> are organized.

That's not the point.

> You might want to check into the documentation
> of Oracle---the explain pretty well how their data base is
> organized (and there are a lot more processes than processors).

Different scenario.

John


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
JohnQ
1/16/2007 9:31:27 AM
"James Kanze" <james.kanze@gmail.com> wrote in message
news:1168886320.170649.189980@l53g2000cwa.googlegroups.com...
> JohnQ wrote:
>> "James Kanze" <james.kanze@gmail.com> wrote in message
>> news:1168780230.381634.41480@11g2000cwr.googlegroups.com...
>> > JQP wrote:
>
>      [...]
>> >> OK. I don't have knowledge of the entire range of design problems that
>> >> threads can solve, so now I'm wondering about those other ones that I
>> >> haven't worked with yet. For instance, I don't know the concept
>> >> "joinable threads".
>
>> > Anytime you want to use the response from a thread, you need a
>> > joinable thread.  It's also very hard to do a clean shutdown
>> > without them.
>
>> OK "joinable" is semantically foreign to me.
>
> It's the standard vocabulary.  It's the term used in all of the
> threading interfaces I know: Posix, Boost, Java...  I'd expect
> the term to be familiar with anyone familiar with threading.

In the UNIX world. Show me the words 'joinable' or 'detached' in any of the
Windows API (Win32, not more recent .Net/C# products) documentation.

>> If you would have said
>> 'waitable thread', I would have groked it right away. Example of a
>> "joinable"/"waitable" thread: an intermediate result of some complex
>> mathematical formula. Example of a "detached" thread: worker threads in a
>> thread pool handling incoming database transactions. Yes?
>
> It depends.  A lot of server software will use joinable threads
> in order to ensure a clean shutdown.  It's especially true if
> you use objects for threads.  GUI worker threads will typically
> be detached, since the GUI event thread cannot very well do a
> join, although some designs will use a special reaper thread to
> do the joins.  (Again, this is done in order to ensure clean
> shutdown.)  (I'm not sure, but I have the impression that you
> can close the thread handle without stopping the thread.  This
> corresponds very exactly to detaching the thread; the vocabulary
> is a little wierd, but in this case, perhaps justifiably so,
> because of the unified way Windows handles handles.)
>
> Note that similar issues concern processes.
>
>> In Windows, one does not have to specify anything to get a "joinable"
>> thread: one just waits for the thread handle to become signaled. (That 
>> is,
>> if the concept of "waiting on" and "joining" is the same).
>
> And if no one ever waits for the thread?

Application-specific. No one waits on the thread that blocks on GetMessage()
for example: if it returns 0, program exits.

> A thread uses system
> resources, and in a joinable thread, those resources must be
> kept by the system until the join has taken place.  If a thread
> is detached, on the other hand, the system frees up the
> resources as soon as the thread has finished.

That sounds like what ExitThread does. Actually, whether a thread exits or
calls ExitThread, the same thing happens (resources are cleaned up). OK...
ExitThread is an API that can be called from WITHIN a thread to exit the
thread. External to the thread, in order to exit the thread one must let the
thread exit on its own, or one must have designed some way of exiting
gracefully or call TerminateThread, the last of which is never recommended
because resources will not be released. (I'm not reading the documentation
as I type this so don't take it as gospel). And remember, I'm not suggesting
that all this is possible using only the Win32 API, that's why wrapper
(actually more than just wrappers, but new abstractions from the synthesis
of API constructs) classes may be necessary, such as a Thread class.

>> Why is it hard to cleanly shutdown a detached thread?
>
> Because you don't know when it has finished.  (And of course,
> you can't call exit() safely until it has finished.)

I new you were going to say that. I agree: the program is not done being
developed until those issues have been solved for the given application. My
intuition says that some kind of general library or language element is not
possible to "solve the problem once and for all", but rather that
application or domain or framework -specific solutions are possibly the only
solution.

>> On the flip side, why is it easy to cleanly shutdown a
>> joinable thread?  Oh, did you mean shutdown the application
>> rather than the threads (which becomes the problem of shutting
>> down the threads)?
>
> Shutdown means shutting down the application, yes.  With the
> constraint that you cannot call exit as long as any threads are
> running.

OK, good, just to have proper context.

John


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
JohnQ
1/16/2007 9:32:41 AM
"Sergey P. Derevyago" <non-existent@iobox.com> wrote in message
news:45A631F0.79BF899A@iobox.com...
> Pete Becker wrote:
>> Not quite. There are two different perspectives on multi-threaded
>> programming. On is "distribute the workload optimally among the
>> available processors." That's when you want just as many threads as
>> processor cores. The other is "logically divide the process into tasks
>> that can be run concurrently." That's when you want as many threads as
>> appropriate, and are willing to put up with some thrashing and delays
>> when you have more threads than cores.
>>
> OK, what about "logically divide the process into jobs that can be
> run
> concurrently" and put them on the thread pool's queue?

Sounds like the same problem: how many threads do you allow in the pool?
(How many active threads).

John


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
JohnQ
1/16/2007 9:37:15 AM
JohnQ wrote:
> >> Not quite. There are two different perspectives on multi-threaded
> >> programming. On is "distribute the workload optimally among the
> >> available processors." That's when you want just as many threads as
> >> processor cores. The other is "logically divide the process into tasks
> >> that can be run concurrently." That's when you want as many threads as
> >> appropriate, and are willing to put up with some thrashing and delays
> >> when you have more threads than cores.
> >>
> > OK, what about "logically divide the process into jobs that can be
> > run concurrently" and put them on the thread pool's queue?
> >
> Sounds like the same problem: how many threads do you allow in the pool?
> (How many active threads).
>
        The point is that the "two different perspectives" above get
combined in one:
divide the whole tasks into parallel jobs but don't use a thread-per-job
model.
        It's recommended to read the following papers to get the idea how really
heavyweight tasks should be processed: http://www.kegel.com/c10k.html
--
         With all respect, Sergey.               http://ders.stml.net/
         mailto : ders at skeptik.net

--
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Sergey
1/16/2007 3:51:24 PM
JohnQ wrote:
> "James Kanze" <james.kanze@gmail.com> wrote in message
> news:1168886320.170649.189980@l53g2000cwa.googlegroups.com...
> > JohnQ wrote:
> >> "James Kanze" <james.kanze@gmail.com> wrote in message
> >> news:1168780230.381634.41480@11g2000cwr.googlegroups.com...
> >> > JQP wrote:

> >      [...]
> >> >> OK. I don't have knowledge of the entire range of design problems
that
> >> >> threads can solve, so now I'm wondering about those other ones that
I
> >> >> haven't worked with yet. For instance, I don't know the concept
> >> >> "joinable threads".

> >> > Anytime you want to use the response from a thread, you need a
> >> > joinable thread.  It's also very hard to do a clean shutdown
> >> > without them.

> >> OK "joinable" is semantically foreign to me.

> > It's the standard vocabulary.  It's the term used in all of the
> > threading interfaces I know: Posix, Boost, Java...  I'd expect
> > the term to be familiar with anyone familiar with threading.

> In the UNIX world. Show me the words 'joinable' or 'detached' in any of
the
> Windows API (Win32, not more recent .Net/C# products) documentation.

In the threading world.  The terms go back before Unix even
existed.  Why Windows decided to use a non-standard vocabulary
is beyond me, but it's not a real problem.  First, you learn
threading (which means learning terms like join), then you learn
Windows threading, or Posix threading, or whatever platform you
need.  Many of the issues are the same, the works of people like
Hoare or Dijkstra are still pertinant today, and their ideas
will still permeate the design of a threaded application.

      [...]
> >> In Windows, one does not have to specify anything to get a "joinable"
> >> thread: one just waits for the thread handle to become signaled. (That
> >> is,
> >> if the concept of "waiting on" and "joining" is the same).

> > And if no one ever waits for the thread?
> > A thread uses system
> > resources, and in a joinable thread, those resources must be
> > kept by the system until the join has taken place.  If a thread
> > is detached, on the other hand, the system frees up the
> > resources as soon as the thread has finished.

> That sounds like what ExitThread does. Actually, whether a thread exits or
> calls ExitThread, the same thing happens (resources are cleaned up).

Which means that you cannot call ExitThread on a thread which
someone might wait for?  I rather doubt that.

I'm not sure -- I'm not that familiar with Windows -- but
by reading some of the documentation and looking at example code
(e.g. in boost::threads), I get the impression that you detach a
thread by closing the thread handle.  In some ways, it's a sort
of surprising idea, but I sort of like it.  A thread has two
sets of system resources, those that it uses directly, and those
that are used to implement the join, and pass information back
to the joining thread.  The handle is responsible for the
second, only.

> OK...
> ExitThread is an API that can be called from WITHIN a thread to exit the
> thread. External to the thread, in order to exit the thread one must let
the
> thread exit on its own, or one must have designed some way of exiting
> gracefully or call TerminateThread, the last of which is never recommended
> because resources will not be released. (I'm not reading the documentation
> as I type this so don't take it as gospel).

I think it's more or less correct, except that I wouldn't say
that resources won't be released: the resources directly
associated with the thread by the system should be released, but
there's no guarantee that the thread will "clean-up" correctly
and leave things in a coherent state.  One frequent symptom of
this incoherence is that some resources allocated by the thread
might leak.

This is very different from pthread_cancel.  Although one would
normally expect functions with names like terminate and cancel
to behave similarly, pthread_cancel doesn't really cancel the
thread; it just sets a global flag that the thread can test, and
unblocks any blocking system calls.  The good thing about it is
that the thread can e.g. read on a socket without a time out,
and be interrupted to clean up and terminate normally.  (The bad
thing, of course, is that there is no guarantee that the thread
will do this; pthread_cancel is purely advisory, and a rogue
thread can ignore it completely.)

> And remember, I'm not suggesting
> that all this is possible using only the Win32 API, that's why wrapper
> (actually more than just wrappers, but new abstractions from the synthesis
> of API constructs) classes may be necessary, such as a Thread class.

> >> Why is it hard to cleanly shutdown a detached thread?

> > Because you don't know when it has finished.  (And of course,
> > you can't call exit() safely until it has finished.)

> I new you were going to say that. I agree: the program is not done being
> developed until those issues have been solved for the given application.
My
> intuition says that some kind of general library or language element is
not
> possible to "solve the problem once and for all", but rather that
> application or domain or framework -specific solutions are possibly the
only
> solution.

That's really my feeling as well.  Generally speaking, I'd like
something like pthread_cancel, so that I block without a
time-out, but still be able to interrupt and clean-up.  But it's
not a killer issue; in fact, I don't use pthread_cancel under
Solaris, because Sun CC and g++ give it different semantics.

--
James Kanze (GABI Software)             email:james.kanze@gmail.com
Conseils en informatique orientie objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place Simard, 78210 St.-Cyr-l'Icole, France, +33 (0)1 30 23 00 34


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
James
1/16/2007 5:35:15 PM
James Kanze wrote:
> JohnQ wrote:
>> No one said TerminateThread was being used for "orderly shutdown".
Obviously
>> it is "violent" termination of a thread.
> 
> I know.  That's what the documentation says.  So what do you
> use?  I couldn't find anything like pthread_cancel in the
> Microsoft documentation.

You use a "shutdown" event, and every blocking operation in the thread 
uses WaitForMultipleObjects with the shutdown event as one of the objects.

Yechezkel Mett

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Yechezkel
1/16/2007 5:35:46 PM
"Sergey P. Derevyago" <non-existent@iobox.com> wrote in message 
news:45ACAF10.31F3069E@iobox.com...
> JohnQ wrote:
>> >> Not quite. There are two different perspectives on multi-threaded
>> >> programming. On is "distribute the workload optimally among the
>> >> available processors." That's when you want just as many threads as
>> >> processor cores. The other is "logically divide the process into tasks
>> >> that can be run concurrently." That's when you want as many threads as
>> >> appropriate, and are willing to put up with some thrashing and delays
>> >> when you have more threads than cores.
>> >>
>> > OK, what about "logically divide the process into jobs that can be
>> > run concurrently" and put them on the thread pool's queue?
>> >
>> Sounds like the same problem: how many threads do you allow in the pool?
>> (How many active threads).
>>
>        The point is that the "two different perspectives" above get
> combined in one:
> divide the whole tasks into parallel jobs but don't use a thread-per-job
> model.

Explain please how that solves any design problem/dilemma related to 
choosing how many active threads are allowed per processor core.

John 


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
JohnQ
1/16/2007 5:43:19 PM
James Kanze wrote:
> In individual cases, it's generally possible to provide an
> application specific solution.  Which involves using time-outs
> and such, because there is no clean way of interrupting a
> blocked thread.
>

WaitForMultipleObjects

Obviously not "your" WaitForMultipleObjects because the individual
threads would still be blocked, but with the Windows version you can
wait on both the event you're blocking for and some shutdown event - no
timeouts or polling required.

Similarly Sleep can be replaced with a wait for the shutdown event with
a suitable timeout.


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
PeteK
1/16/2007 6:34:54 PM
Yechezkel Mett wrote:
> James Kanze wrote:
> > JohnQ wrote:
> >> No one said TerminateThread was being used for "orderly shutdown".
> Obviously
> >> it is "violent" termination of a thread.
> >
> > I know.  That's what the documentation says.  So what do you
> > use?  I couldn't find anything like pthread_cancel in the
> > Microsoft documentation.
>
> You use a "shutdown" event, and every blocking operation in the thread
> uses WaitForMultipleObjects with the shutdown event as one of the objects.

:)

One day, it will be discovered that this technique is not simply "a"
way to do it, but "a way to do it that makes the programmer feel really
good about having done it that way."  IOW, it is not simply convenient.
 It is borderline fundamental.

This is what I meant about WaitForMultipleObjects and its equivalents
on other OS's. Once the programmer has had a taste of it, there is no
turning back. Multi-threading, even in a "complex" application with 25+
threads, no longer seems complex at, not any more than say, a recursive
function with multiple points of return.

The beauty of this technique is that it integrates naturally with the
C++ constructor/destructor model and it is entirely based on a library
with no modification to the language itself.

Of course, one would want to make the interface is clean so that it
readily ports from OS to OS, and one might impress upon the kernel-mode
designers of the target OS that such a primitive is a not merely a
peculiarity of one particular OS but necessity for all multi-tasking
OS's in general.

-Le Chaud Lapin-


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Le
1/16/2007 6:45:46 PM
JohnQ wrote:
> >        The point is that the "two different perspectives" above get
> > combined in one: divide the whole tasks into parallel jobs but don't use
> > a thread-per-job model.
> >
> Explain please how that solves any design problem/dilemma related to
> choosing how many active threads are allowed per processor core.
>
	It was stated that there are (only) two different perspectives on
multi-threaded programming:
1. Create N threads (as you have N CPUs on the board) and divide your task
into N parallel jobs.
2. Divide the task in as many parallel jobs as you can (say, M) and create M
threads to run them concurrently.

	I just said that there is some more option to be considered: map
these M jobs
on your N CPUs. This is neither task-per-CPU nor thread-per-job approach.
--
         With all respect, Sergey.               http://ders.stml.net/
         mailto : ders at skeptik.net

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Sergey
1/16/2007 6:55:33 PM
Sergey P. Derevyago wrote:
> JohnQ wrote:
>>>        The point is that the "two different perspectives" above get
>>> combined in one: divide the whole tasks into parallel jobs but
>>> don't use a thread-per-job model.
>>>
>> Explain please how that solves any design problem/dilemma related to
>> choosing how many active threads are allowed per processor core.
>>
> It was stated that there are (only) two different perspectives on
> multi-threaded programming:
> 1. Create N threads (as you have N CPUs on the board) and divide your
> task into N parallel jobs.
> 2. Divide the task in as many parallel jobs as you can (say, M) and
> create M threads to run them concurrently.
>
> I just said that there is some more option to be considered: map
> these M jobs
> on your N CPUs. This is neither task-per-CPU nor thread-per-job
> approach.

What does that mapping accomplish?  I understood the difference
between those two perspectives as based on the fact that you either
already have the 'M' number, or deduce it based on the core count
(thus making it equal to the 'N').  If 'M' is governed by your tasks,
what would be the point of mapping them to cores, especially if the
numbers (N and M) are unrelated?  Or are you proposing that all the
"tasks" that you have are [essentially] put in a queue of "tasks to
be parallelized" and then executed, N queue elements at a time?  If
so, it looks like a combination of 2 and 1.  Ok, maybe, it's 2, only
reiterated, refactored, by 1.  Did I understand you correctly?

V
-- 
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask 



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Victor
1/16/2007 8:10:19 PM
"Sergey P. Derevyago" <non-existent@iobox.com> wrote in message 
news:45AD16F3.B721D5@iobox.com...
> JohnQ wrote:
>> >        The point is that the "two different perspectives" above get
>> > combined in one: divide the whole tasks into parallel jobs but don't 
>> > use
>> > a thread-per-job model.
>> >
>> Explain please how that solves any design problem/dilemma related to
>> choosing how many active threads are allowed per processor core.
>>
> It was stated that there are (only) two different perspectives on
> multi-threaded programming:
> 1. Create N threads (as you have N CPUs on the board) and divide your task
> into N parallel jobs.

OK, 2 cores and 2 threads in the thread pool.

> 2. Divide the task in as many parallel jobs as you can (say, M) and create 
> M
> threads to run them concurrently.

OK, 2 cores and more than 2 threads in the thread pool.

> I just said that there is some more option to be considered: map
> these M jobs
> on your N CPUs. This is neither task-per-CPU nor thread-per-job approach.

Help me out here, as I don't get it: what do you mean by "map M jobs on N 
CPUs"? What is this "mapping of jobs"? It sounds like option 2 above to me.

John 


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
JohnQ
1/16/2007 8:11:02 PM
"Le Chaud Lapin" <jaibuduvin@gmail.com> wrote in message 
news:1168971030.975857.16630@q2g2000cwa.googlegroups.com...
> Yechezkel Mett wrote:
>> James Kanze wrote:
>> > JohnQ wrote:
>> >> No one said TerminateThread was being used for "orderly shutdown".
>> Obviously
>> >> it is "violent" termination of a thread.
>> >
>> > I know.  That's what the documentation says.  So what do you
>> > use?  I couldn't find anything like pthread_cancel in the
>> > Microsoft documentation.
>>
>> You use a "shutdown" event, and every blocking operation in the thread
>> uses WaitForMultipleObjects with the shutdown event as one of the 
>> objects.
>
> :)

Someone else mentioned that too. Sounds like a great way to accomplish 
generic exit of BLOCKING threads. In another post I wondered about the state 
of the subsystem (I said library) after a thread was generically unblocked. 
Now I don't know what I was thinking in that regard. :/

> One day, it will be discovered that this technique is not simply "a"
> way to do it, but "a way to do it that makes the programmer feel really
> good about having done it that way."  IOW, it is not simply convenient.
> It is borderline fundamental.

Sounds good to me.

> This is what I meant about WaitForMultipleObjects and its equivalents
> on other OS's. Once the programmer has had a taste of it, there is no
> turning back.

Hmmmm. I wondering if it should be THE way to unblock always instead of 
trying to figure out how to do it in a given scenario. It seems that it 
would eliminate the need for the virtual Unblock() method in a Thread class. 
I like it.

> Multi-threading, even in a "complex" application with 25+
> threads, no longer seems complex at, not any more than say, a recursive
> function with multiple points of return.
>
> The beauty of this technique is that it integrates naturally with the
> C++ constructor/destructor model and it is entirely based on a library
> with no modification to the language itself.
>
> Of course, one would want to make the interface is clean so that it
> readily ports from OS to OS, and one might impress upon the kernel-mode
> designers of the target OS that such a primitive is a not merely a
> peculiarity of one particular OS but necessity for all multi-tasking
> OS's in general.

Is there such a function as WaitForMultipleObjects on other OSes besides 
Windows?

John 


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
JohnQ
1/16/2007 8:11:25 PM
"James Kanze" <james.kanze@gmail.com> wrote in message 
news:1168945291.510211.306400@q2g2000cwa.googlegroups.com...
> JohnQ wrote:
>> "James Kanze" <james.kanze@gmail.com> wrote in message
>> news:1168886320.170649.189980@l53g2000cwa.googlegroups.com...
>> > JohnQ wrote:
>> >> "James Kanze" <james.kanze@gmail.com> wrote in message
>> >> news:1168780230.381634.41480@11g2000cwr.googlegroups.com...
>> >> > JQP wrote:
>
>> >      [...]
>> >> >> OK. I don't have knowledge of the entire range of design problems
> that
>> >> >> threads can solve, so now I'm wondering about those other ones that
> I
>> >> >> haven't worked with yet. For instance, I don't know the concept
>> >> >> "joinable threads".
>
>> >> > Anytime you want to use the response from a thread, you need a
>> >> > joinable thread.  It's also very hard to do a clean shutdown
>> >> > without them.
>
>> >> OK "joinable" is semantically foreign to me.
>
>> > It's the standard vocabulary.  It's the term used in all of the
>> > threading interfaces I know: Posix, Boost, Java...  I'd expect
>> > the term to be familiar with anyone familiar with threading.
>
>> In the UNIX world. Show me the words 'joinable' or 'detached' in any of
> the
>> Windows API (Win32, not more recent .Net/C# products) documentation.
>
> In the threading world.  The terms go back before Unix even
> existed.  Why Windows decided to use a non-standard vocabulary
> is beyond me, but it's not a real problem.  First, you learn
> threading (which means learning terms like join), then you learn
> Windows threading, or Posix threading, or whatever platform you
> need.  Many of the issues are the same, the works of people like
> Hoare or Dijkstra are still pertinant today, and their ideas
> will still permeate the design of a threaded application.

Nah, I like the Windowsisms first because it's the only platform I'm on now. 
Ipick up things on other platforms as required. The other platforms (or 
traditional science terminology) aren't as intuitive. For example, condition 
variables vs. events, and now joinable/detached threads. I find Windowisms 
more approachable than most stuff (another example is GDI vs. X.). UNIX is 
hard!

>      [...]
>> >> In Windows, one does not have to specify anything to get a "joinable"
>> >> thread: one just waits for the thread handle to become signaled. (That
>> >> is,
>> >> if the concept of "waiting on" and "joining" is the same).
>
>> > And if no one ever waits for the thread?
>> > A thread uses system
>> > resources, and in a joinable thread, those resources must be
>> > kept by the system until the join has taken place.  If a thread
>> > is detached, on the other hand, the system frees up the
>> > resources as soon as the thread has finished.
>
>> That sounds like what ExitThread does. Actually, whether a thread exits 
>> or
>> calls ExitThread, the same thing happens (resources are cleaned up).
>
> Which means that you cannot call ExitThread on a thread which
> someone might wait for?  I rather doubt that.

Nope. Just from within a thread. (If using the C runtime library, the 
function to call is _endthread from within a thread rather than ExitThread).

> I'm not sure -- I'm not that familiar with Windows -- but
> by reading some of the documentation and looking at example code
> (e.g. in boost::threads), I get the impression that you detach a
> thread by closing the thread handle.

Or do the handle closing in the wrapper Thread class (that you have to 
create). I'm not sure what closing the handle immediately accomplishes other 
than not having to keep track of the thread and clean up the handle after 
the thread exits (is that basically what "detached" means?).

> In some ways, it's a sort
> of surprising idea, but I sort of like it.  A thread has two
> sets of system resources, those that it uses directly, and those
> that are used to implement the join, and pass information back
> to the joining thread.  The handle is responsible for the
> second, only.
>
>> OK...
>> ExitThread is an API that can be called from WITHIN a thread to exit the
>> thread. External to the thread, in order to exit the thread one must let
> the
>> thread exit on its own, or one must have designed some way of exiting
>> gracefully or call TerminateThread, the last of which is never 
>> recommended
>> because resources will not be released. (I'm not reading the 
>> documentation
>> as I type this so don't take it as gospel).
>
> I think it's more or less correct, except that I wouldn't say
> that resources won't be released: the resources directly
> associated with the thread by the system should be released, but
> there's no guarantee that the thread will "clean-up" correctly
> and leave things in a coherent state.  One frequent symptom of
> this incoherence is that some resources allocated by the thread
> might leak.

>From the documentation:

"TerminateThread can result in the following problems:

� If the target thread owns a critical section, the critical section will 
not be released.
� If the target thread is executing certain kernel32 calls when it is 
terminated, the kernel32 state for the thread's process could be 
inconsistent.
� If the target thread is manipulating the global state of a shared DLL, the 
state of the DLL could be destroyed, affecting other users of the DLL."

> This is very different from pthread_cancel.  Although one would
> normally expect functions with names like terminate and cancel
> to behave similarly, pthread_cancel doesn't really cancel the
> thread; it just sets a global flag that the thread can test, and
> unblocks any blocking system calls.

Oh, well there you go. That's what we've been looking for all along. On 
Windows that option doesn't exist so one has to analyze the situation and do 
something program-specific or use what another poster mentioned in another 
thread: block on multiple events via WaitForMultipleObjects. That doesn't 
help break out of looping threads though.

> The good thing about it is
> that the thread can e.g. read on a socket without a time out,
> and be interrupted to clean up and terminate normally.  (The bad
> thing, of course, is that there is no guarantee that the thread
> will do this; pthread_cancel is purely advisory, and a rogue
> thread can ignore it completely.)

Not good. Probably, any library that has blocking code should provide a way 
to unblock. Which begs the question why, say the sockets libraries, didn't 
include that.

>> And remember, I'm not suggesting
>> that all this is possible using only the Win32 API, that's why wrapper
>> (actually more than just wrappers, but new abstractions from the 
>> synthesis
>> of API constructs) classes may be necessary, such as a Thread class.
>
>> >> Why is it hard to cleanly shutdown a detached thread?
>
>> > Because you don't know when it has finished.  (And of course,
>> > you can't call exit() safely until it has finished.)
>
>> I new you were going to say that. I agree: the program is not done being
>> developed until those issues have been solved for the given application.
> My
>> intuition says that some kind of general library or language element is
> not
>> possible to "solve the problem once and for all", but rather that
>> application or domain or framework -specific solutions are possibly the
> only
>> solution.
>
> That's really my feeling as well.  Generally speaking, I'd like
> something like pthread_cancel, so that I block without a
> time-out, but still be able to interrupt and clean-up.  But it's
> not a killer issue; in fact, I don't use pthread_cancel under
> Solaris, because Sun CC and g++ give it different semantics.

I don't see how pthread_cancel or something similar could ever work because 
it can't know what state the library that has the blocking function is in. 
Unblocking in some generic way can't guarantee everything is "back to 
normal" after unblocking. So pthread_cancel sounds as dangerous as 
TerminateThread.

John 


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
JohnQ
1/16/2007 8:11:47 PM
James Kanze wrote:

>> No one said TerminateThread was being used for "orderly shutdown". Obviously
>> it is "violent" termination of a thread.
> 
> I know.  That's what the documentation says.  So what do you
> use?  I couldn't find anything like pthread_cancel in the
> Microsoft documentation.

The only way to cancel a thread beautifully is to ask it to stop.
For that you can use events, message passing, a shared atomic variable
or protected by a mutex...

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Mathias
1/17/2007 5:24:07 AM
JohnQ wrote:
> "James Kanze" <james.kanze@gmail.com> wrote in message
> > This is very different from pthread_cancel.  Although one would
> > normally expect functions with names like terminate and cancel
> > to behave similarly, pthread_cancel doesn't really cancel the
> > thread; it just sets a global flag that the thread can test, and
> > unblocks any blocking system calls.
>
> Oh, well there you go. That's what we've been looking for all along. On
> Windows that option doesn't exist so one has to analyze the situation and do
> something program-specific or use what another poster mentioned in another
> thread: block on multiple events via WaitForMultipleObjects. That doesn't
> help break out of looping threads though.

Actually it does.  We already agreed that orderly shutdown is preferred
over disruptive. But intuitively, if a thread is not blocked, any type
of shutdown at that point is disruptive - only the thread itself can
know what must be done to "unwind" and make it not.

The flag that James mentioned is essentially the event that we are
speaking of.  It is not given - you have to build it into your
framework.

-Le Chaud Lapin-


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Le
1/17/2007 5:25:42 AM
"Le Chaud Lapin" <jaibuduvin@gmail.com> wrote in message
news:1168971030.975857.16630@q2g2000cwa.googlegroups.com...
> Yechezkel Mett wrote:
>> James Kanze wrote:
>> > JohnQ wrote:
>> >> No one said TerminateThread was being used for "orderly shutdown".
>> Obviously
>> >> it is "violent" termination of a thread.
>> >
>> > I know.  That's what the documentation says.  So what do you
>> > use?  I couldn't find anything like pthread_cancel in the
>> > Microsoft documentation.
>>
>> You use a "shutdown" event, and every blocking operation in the thread
>> uses WaitForMultipleObjects with the shutdown event as one of the
>> objects.
>
> :)

That sounded like a good idea, but how will it solve THE problem of a
blocking socket read, for example, since you can't wait on the read function
and an event both with WaitForMultipleObjects?

John


--
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
JohnQ
1/17/2007 8:02:59 AM
JohnQ wrote:
> "Le Chaud Lapin" <jaibuduvin@gmail.com> wrote in message
> news:1168971030.975857.16630@q2g2000cwa.googlegroups.com...
> > Yechezkel Mett wrote:
> >> You use a "shutdown" event, and every blocking operation in the thread
> >> uses WaitForMultipleObjects with the shutdown event as one of the
> >> objects.
> >
> > :)
>
> That sounded like a good idea, but how will it solve THE problem of a
> blocking socket read, for example, since you can't wait on the read
function
> and an event both with WaitForMultipleObjects?

You have to use what Microsoft calls overlapped I/O, and you have to
use the Windows-specific version of Berkeley's recv function, WSARecv
http://msdn2.microsoft.com/en-us/library/ms741688.aspx.

Essentially, you invoke a function to declare to to the TCP/IP stack
that you are ready to read data from the socket, and the function
returns a code telling you, "Ok, I'm trying to read now, blocking,
waiting for data, but do not touch the buffer you gave me".  Then when
it actually puts data in the buffer (or is simply ready to put data
somewhere), it either calls a routine that you supplied in the read
call, or signals an event whose handle you supplied in the read call.
That event can be one of many arguments for WaitForMultipleObjects. [I
know you know most of this, I'm writing for edification of other
posters.]

It it a mess?  Yes.  Do we have an alternative?  No, it is what
thousands of programmers deal with every day.

This is one of those areas where truth of form begins to grind against
our models slowly, until the realization of systems based on that model
becomes so ugly that we are forced to redress.  In this case, we are
forced to see that, in a multi-threaded applications, there should
exist a portable means of waiting for multiple synchronization triggers
at strategic locations in code. and any blocking function should
provide a portable mechanism to break in an orderly fashion.

-Le Chaud Lapin-


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Le
1/17/2007 4:24:06 PM
"Mathias Gaunard" <loufoque@remove.gmail.com> wrote in message 
news:45ad7519$0$30124$426a34cc@news.free.fr...
> James Kanze wrote:
>
>>> No one said TerminateThread was being used for "orderly shutdown". 
>>> Obviously
>>> it is "violent" termination of a thread.
>>
>> I know.  That's what the documentation says.  So what do you
>> use?  I couldn't find anything like pthread_cancel in the
>> Microsoft documentation.
>
> The only way to cancel a thread beautifully is to ask it to stop.
> For that you can use events, message passing, a shared atomic variable
> or protected by a mutex...

How do you stop a thread blocking on a socket read call?

John 


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
JohnQ
1/17/2007 4:35:50 PM
"Le Chaud Lapin" <jaibuduvin@gmail.com> wrote in message 
news:1168997262.439892.128430@51g2000cwl.googlegroups.com...
> JohnQ wrote:
>> "James Kanze" <james.kanze@gmail.com> wrote in message
>> > This is very different from pthread_cancel.  Although one would
>> > normally expect functions with names like terminate and cancel
>> > to behave similarly, pthread_cancel doesn't really cancel the
>> > thread; it just sets a global flag that the thread can test, and
>> > unblocks any blocking system calls.
>>
>> Oh, well there you go. That's what we've been looking for all along. On
>> Windows that option doesn't exist so one has to analyze the situation and

>> do
>> something program-specific or use what another poster mentioned in 
>> another
>> thread: block on multiple events via WaitForMultipleObjects. That doesn't
>> help break out of looping threads though.
>
> Actually it does.  We already agreed that orderly shutdown is preferred
> over disruptive. But intuitively, if a thread is not blocked, any type
> of shutdown at that point is disruptive - only the thread itself can
> know what must be done to "unwind" and make it not.
>
> The flag that James mentioned is essentially the event that we are
> speaking of.  It is not given - you have to build it into your
> framework.

It's unnecessary in looping threads though because you can check a simple 
flag each time through the loop (assume only one designated thread, say a 
thread manager, will be ever setting that flag).

On the original issue though, I don't think it is a solution (?) because 
what do you do if a thread is blocking on a socket read call? You can't pass

a socket handle to WaitForMultipleObjects (though that sounds like it would 
be ideal if one could).

John 


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
JohnQ
1/17/2007 4:37:06 PM
JohnQ wrote:

>>Of course, one would want to make the interface is clean so that it
>>readily ports from OS to OS, and one might impress upon the kernel-mode
>>designers of the target OS that such a primitive is a not merely a
>>peculiarity of one particular OS but necessity for all multi-tasking
>>OS's in general.
> 
> Is there such a function as WaitForMultipleObjects on other OSes besides 
> Windows?

Not on POSIX, at least, but that doesn't mean you cannot arrange 
something similar. You just shouldn't make the mistake to identify a 
posix mutex with a M$ handle you can wait on. In a recent application 
(that is multithreaded, of course) I used mutexes and semaphores as 
building stone for an "event" system. Waiting for multiple objects here 
means that objects can trigger events (my wording has been "Message"), 
and you wait on the event queue (my woring "MessagePort") to an event to 
arrive. One of the events is then of course a shutdown-event for a thread.

So yes, it is definitely a useful design, and even though 
WaitForMultipleObjects isn't portable, you can easily (or at least, I 
could easily) build something similar just on POSIX grounds. No, I 
haven't heart about WaitForMultipleObjects before, and I don't think I 
will ever use that function - it's not available as an Os primitive on 
most platforms.

To conclude, it is not a "necessity" for multitasking, I can built it if 
I need it. But yes, it's useful.

So long,
	Thomas

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Thomas
1/17/2007 4:37:28 PM
{ please try staying on topic.  discussing sockets pushes the
  boundary in the Windows-specific direction.  thanks.  -mod }

JohnQ wrote:
>> Yechezkel Mett wrote:
>>> You use a "shutdown" event, and every blocking operation in the thread
>>> uses WaitForMultipleObjects with the shutdown event as one of the
>>> objects.
> 
> That sounded like a good idea, but how will it solve THE problem of a
> blocking socket read, for example, since you can't wait on the read
function
> and an event both with WaitForMultipleObjects?

Sockets are a bit of an odd man out in Windows because they don't have 
handles. You need to use WSAEventSelect to associate an Event with a 
socket, and use that.

Yechezkel Mett

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Yechezkel
1/17/2007 6:16:57 PM
Victor Bazarov wrote:
> What does that mapping accomplish?
>
	1. You just divide your task into M parallel jobs. The number of
jobs doesn't
depend on the HW you're running.
	2. You use exactly N threads to process these M jobs. This number N
depends
on the HW. You're (the user) supposed to tweak N to obtain the maximum
possible throughput, possible on _your_ HW.
--
         With all respect, Sergey.               http://ders.stml.net/
         mailto : ders at skeptik.net

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Sergey
1/17/2007 6:18:57 PM
JohnQ wrote:
> Help me out here, as I don't get it: what do you mean by "map M jobs on N
> CPUs"? What is this "mapping of jobs"? It sounds like option 2 above to
me.
>
	Please read my reply to Victor Bazarov,
	Message-ID: <45AE06CD.4F9AA115@iobox.com>
--
         With all respect, Sergey.               http://ders.stml.net/
         mailto : ders at skeptik.net

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Sergey
1/17/2007 6:19:21 PM
Le Chaud Lapin wrote:

> JohnQ wrote:
>> "James Kanze" <james.kanze@gmail.com> wrote in message
>> > This is very different from pthread_cancel.  Although one would
>> > normally expect functions with names like terminate and cancel
>> > to behave similarly, pthread_cancel doesn't really cancel the
>> > thread; it just sets a global flag that the thread can test, and
>> > unblocks any blocking system calls.
>>
>> Oh, well there you go. That's what we've been looking for all
>> along. On Windows that option doesn't exist so one has to analyze
>> the situation and do something program-specific or use what another
>> poster mentioned in another thread: block on multiple events via
>> WaitForMultipleObjects. That doesn't help break out of looping
>> threads though.
> 
> Actually it does.  We already agreed that orderly shutdown is
> preferred over disruptive. But intuitively, if a thread is not
> blocked, any type of shutdown at that point is disruptive - only the
> thread itself can know what must be done to "unwind" and make it
> not.

Why not use C++' exception mechanism to cancel threads? The owner of a
thread object (or handle or reference or whatever) calls a cancel()
function which causes a thread_cancelled exception to be thrown in
that thread. Then cleanup can happen by the normal exception
handlers.

It seems from a quick web search that this idea is obvious enough that
it's been at least tried before. I can see a problem with throw()
declarations becoming somewhat less of a guarantee, and there would
have to be a very careful specification of at which points the
exception would become visible. Perhaps it would even be useful to
have atomic blocks that would execute fully before the exception
became visible if it were thrown halfway. If any kind of jumping or
looping would be disallowed inside an atomic block, the exception
would eventually be thrown.

I haven't thought this through properly, so maybe there's something
obvious I'm missing, but it seems logical.

Lourens


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Lourens
1/17/2007 6:27:59 PM
Note to moderator: My previous post was rejected due to excessive
quoting. While I do not agree that i quoted to much, I've removed a few
snippets. If you still believe I quote to much, please advice on which
sections I should trim more.

James Kanze skrev:
> JohnQ wrote:
> > "Le Chaud Lapin" <jaibuduvin@gmail.com> wrote in message
> > news:1168399666.909953.168890@p59g2000hsd.googlegroups.com...
[snip]
>
> > Doesn't ACE attempt to provide a wrapper across current platforms?
> > That sounds wrought with peril given the discussions here lately.
> > Probably better to be platform-specific at this juncture.
>
> That's why there's an attempt to standardize.  (FWIW: I gave up
> on ACE because I found too many errors and false assumptions in
> it.)

Actually, as you no doubt know, the "perils of threading" mentioned in
this group are unrelated to whether or not you wrap threading code.
Thus, using ACE or boost::thread will not make your threading code any
more fragile than using the "raw" interface. On the contrary, chances
are that the wrapper will catch some problematic areas and increase
reliability.
>
> > I know that after following the thread threads I'm not going
> > to be turning on the optimization flags on the compiler anytime soon for
> > one thing.
>
> A good policy even in single threaded code.  Until you need the
> performance they give.

Depending on the code you produce, you might very well be able to use
non-optimised code as production code. Luckily this has been my case on
many of my older projects with older compilers, that simply could not
produce correct code when optimisations were on.
[snip]
> FWIW: the person who developped Boost::threads comes from a
> strong Windows background.  He adopted a model based on Posix
> because he found it significantly superior.  (That is, at least,
> what I have been told.  And from the Boost::threads
> documentation: "Event variables are simply far too error-prone.
> boost::condition variables are a much safer alternative.")  It's
> also significant that Vista adopts condition variables; this may
> be only because they feel certain that that will be the model
> adopted by the C++ standard, and not for any particular
> technical reasons.  And the Boost library does implement
> condition variables under Windows, using Windows OS primitives,
> so it must be possible.
I have created multithreading code almost exclusively on Windows, but
never used anything but a small subset of the available API (thread
creation/destruction, critical sections, semaphores and thread local
storage)- and I only once had a use for WaitForMultipleObjects, and
that is so long time ago I no longer remember the reason: Perhaps I did
not have sufficient experience writing MT-code.
Incidentically, my code looked very much like boost threads - with
condition variables being the primary method of "syncronisation".

>
[snip]
> > > I fell into this trap.  The best advice I can give in this
> > > regard is to say that the concept of the thread itself should not be
> > > modeled as a class.
>
> > That's exactly how I did it years ago. That's probably where I'd start
> > from again if/when I dust off and revive that code. I was probably
> > influenced by the Borland class library and maybe even MFC. So
> > you think they got it wrong huh?
>
> There are two philosophies: a thread is an asynchronous
> function, or a thread is a class.  The Boost model tries for a
> sort of compromize between the two: a thread is a class, but one
> that acts like an implicitly called functional object, and whose
> lifetime doesn't need to extend to the lifetime of the entire
> thread.

I've never needed to create threads on the fly and thus only have the
"thread as a class" model (a template class represents the class using
a "threadable" base class preventing nasty stuff when you stop the
thread), and I find this model perfectly adequate. This model also
makes it quite easy to stop threads with a minimum of cooperation from
the thread. The only real problem would be in threads doing blocking
IO: here it would be nice with some cooperation from the OS.

>
> In my own work, I distinguish between joinable threads and those
> that you "fire and forget".  Joinable threads are a class, so
> you have something to join with; detached threads are started by
> a simple function call.
>
> Another philosophy involves "futures": basically, it consists of
> a function to start the thread; the function returns an object
> which can later be used for joins.

I have implemented futures, but used a fixed thread-pool for these. I
believe the overhead of creating a new thread means that having generic
worker threads ready for stuff like this is a superior approach.

>
> And of course, it's arguable whether one can even use detached
> threads in a correct program.  It certainly makes clean shutdown
> more difficult.  (On the other hand, many of my programs run
> forever, so this isn't an issue.)
>
[snip]
>
> Glancing through the Windows documentation, my impression is
> that in addition to condition variables, it is missing some way
> of statically initializing mutexes.  This would seem essential
> to me in order to maintain encapsulation (and well over half of
> my pthread_mutex_t are statically initialized).  This would be
> less of a problem if the compiler allows unsynchronized use of
> local static variables with dynamic initialization, but since
> one of my target compilers (Sun CC) doesn't, I can't take
> advantage of it.

Is that a big problem? I could imagine a (or some) global mutexes to be
used for initialisation of these static variables. Of course, in theory
you might risk a deadlock but in practical life the problem is not big,
and a tiny bit of code might allow you to autoselect what mutex to use
for a
given variable.
Anyway


>
> Ideally, you also want some means of signaling a thread that you
> want it to shutdown, along the lines of pthread_cancel.  I
> haven't seen an equivalent in Windows, and of course, the
> semantics of pthread_cancel are not defined in C++ (and
> different compilers define them differently), which doesn't help
> either.  (I might add that there has been enough discussion in
> the C++ committee to make me think that there isn't really any
> consensus as to what the semantics should be.)  In the meantime,
> you have to improvise, using some sort of global flag, and
> ensuring that no thread does an indefinitly blocking call.
> (This typically means that you can't use std::cin.)
>
As mentioned already, blocking IO is one area where help from the OS
would be appreciated. In real life this has not been a problem (I
assume normal file IO will terminate within a reasonable period of
time, and my socket IO time outs after a reasonable amount of time
anyway). I would not be able to use cin, however.

/Peter


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
peter
1/17/2007 8:33:58 PM
Le Chaud Lapin <jaibuduvin@gmail.com> writes:

> there should exist a portable means of waiting for multiple
> synchronization triggers at strategic locations in code

ACE's ACE_Reactor� provides this, and Java's Selector� comes close,
but it only allows one to wait on events related to
"SelectableChannels": DatagramChannel, Pipes (source and sink),
SocketChannel, and ServerSocketChannel. Missing are the more arbitrary
events and signals that ACE_Reactor and Windows' WFMO accommodate.


Footnotes: 
� http://www.dre.vanderbilt.edu/Doxygen/Current/html/ace/classACE__Reactor.html
� http://java.sun.com/javase/6/docs/api/java/nio/channels/Selector.html

-- 
Steven E. Harris

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Steven
1/17/2007 8:47:04 PM
JohnQ wrote:
> "Mathias Gaunard" <loufoque@remove.gmail.com> wrote in message 
> news:45ad7519$0$30124$426a34cc@news.free.fr...
>> James Kanze wrote:
>>
>>>> No one said TerminateThread was being used for "orderly shutdown". 
>>>> Obviously
>>>> it is "violent" termination of a thread.
>>> I know.  That's what the documentation says.  So what do you
>>> use?  I couldn't find anything like pthread_cancel in the
>>> Microsoft documentation.
>> The only way to cancel a thread beautifully is to ask it to stop.
>> For that you can use events, message passing, a shared atomic variable
>> or protected by a mutex...
> 
> How do you stop a thread blocking on a socket read call?

Try closing the socket.  The read should then fail.

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
red
1/17/2007 8:52:22 PM
JohnQ wrote:
> "Le Chaud Lapin" <jaibuduvin@gmail.com> wrote in message
> news:1168971030.975857.16630@q2g2000cwa.googlegroups.com...
> > Yechezkel Mett wrote:
> >> James Kanze wrote:
> >> > JohnQ wrote:
> >> >> No one said TerminateThread was being used for "orderly shutdown".
> >> Obviously
> >> >> it is "violent" termination of a thread.
> >> >
> >> > I know.  That's what the documentation says.  So what do you
> >> > use?  I couldn't find anything like pthread_cancel in the
> >> > Microsoft documentation.
> >>
> >> You use a "shutdown" event, and every blocking operation in the thread
> >> uses WaitForMultipleObjects with the shutdown event as one of the
> >> objects.
> >
> > :)
>
> That sounded like a good idea, but how will it solve THE problem of a
> blocking socket read, for example, since you can't wait on the read function
> and an event both with WaitForMultipleObjects?
>

This is getting somewhat off topic, but since you asked ...

It's been a long time since I wrote any Windows socket stuff, but there
used to be a function something like WSACancelBlockingCall.  These days
you'd probably use overlapped I/O and WaitForMultipleEvents.


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
PeteK
1/17/2007 8:52:44 PM
JohnQ <johnqREMOVETHISprogrammer@yahoo.com> writes:

> How do you stop a thread blocking on a socket read call?

Close the socket from another thread.
No, it's not pretty.

-- 
Steven E. Harris

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Steven
1/17/2007 8:53:09 PM
"Le Chaud Lapin" <jaibuduvin@gmail.com> wrote in message 
news:1169022871.731003.45230@a75g2000cwd.googlegroups.com...
> JohnQ wrote:
>> "Le Chaud Lapin" <jaibuduvin@gmail.com> wrote in message
>> news:1168971030.975857.16630@q2g2000cwa.googlegroups.com...
>> > Yechezkel Mett wrote:
>> >> You use a "shutdown" event, and every blocking operation in the thread
>> >> uses WaitForMultipleObjects with the shutdown event as one of the
>> >> objects.
>> >
>> > :)
>>
>> That sounded like a good idea, but how will it solve THE problem of a
>> blocking socket read, for example, since you can't wait on the read
> function
>> and an event both with WaitForMultipleObjects?
>
> You have to use what Microsoft calls overlapped I/O, and you have to
> use the Windows-specific version of Berkeley's recv function, WSARecv
> http://msdn2.microsoft.com/en-us/library/ms741688.aspx.
>
> Essentially, you invoke a function to declare to to the TCP/IP stack
> that you are ready to read data from the socket, and the function
> returns a code telling you, "Ok, I'm trying to read now, blocking,
> waiting for data, but do not touch the buffer you gave me".  Then when
> it actually puts data in the buffer (or is simply ready to put data
> somewhere), it either calls a routine that you supplied in the read
> call, or signals an event whose handle you supplied in the read call.
> That event can be one of many arguments for WaitForMultipleObjects. [I
> know you know most of this, I'm writing for edification of other
> posters.]
>
> It it a mess?  Yes.  Do we have an alternative?  No, it is what
> thousands of programmers deal with every day.

Well at least it can be done, I guess. My original thought though when using 
threads with blocking sockets was to avoid of Windows asynchronous API and 
have something more portable at the inner/lower layer (Berkely-like blocking 
sockets).

> This is one of those areas where truth of form begins to grind against
> our models slowly, until the realization of systems based on that model
> becomes so ugly that we are forced to redress.  In this case, we are
> forced to see that, in a multi-threaded applications, there should
> exist a portable means of waiting for multiple synchronization triggers
> at strategic locations in code. and any blocking function should
> provide a portable mechanism to break in an orderly fashion.

To add insult to injury (gee thx Microsoft), the following comes from the 
Win API documentation:

"The WSACancelBlockingCall function has been removed in compliance with the 
Windows Sockets 2 specification, revision 2.2.0.

The function is not exported directly by WS2_32.DLL and Windows Sockets 2 
applications should not use this function. Windows Sockets 1.1 applications 
that call this function are still supported through the WINSOCK.DLL and 
WSOCK32.DLL.

Blocking hooks are generally used to keep a single-threaded GUI application 
responsive during calls to blocking functions. Instead of using blocking 
hooks, an applications should use a separate thread (separate from the main 
GUI thread) for network activity."

It sounds like the desired unblocking function wanted used to actually be 
available! Though because it is a WSAxxx function, probably means it only 
worked with WSARecv and WSARecvFrom. Sigh.

John 


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
JohnQ
1/17/2007 8:53:50 PM
Thomas Richter wrote:
> So yes, it is definitely a useful design, and even though
> WaitForMultipleObjects isn't portable, you can easily (or at least, I
> could easily) build something similar just on POSIX grounds. No, I
> haven't heart about WaitForMultipleObjects before, and I don't think I
> will ever use that function - it's not available as an Os primitive on
> most platforms.
>
> To conclude, it is not a "necessity" for multitasking, I can built it if
> I need it. But yes, it's useful.

Nor are call stacks a necessity on on computers.  They can be built as
needed.

-Le Chaud Lapin-


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Le
1/18/2007 12:11:20 AM
Lourens Veen wrote:
> Why not use C++' exception mechanism to cancel threads? The owner of a
> thread object (or handle or reference or whatever) calls a cancel()
> function which causes a thread_cancelled exception to be thrown in
> that thread. Then cleanup can happen by the normal exception
> handlers.
>
> It seems from a quick web search that this idea is obvious enough that
> it's been at least tried before. I can see a problem with throw()
> declarations becoming somewhat less of a guarantee, and there would
> have to be a very careful specification of at which points the
> exception would become visible. Perhaps it would even be useful to
> have atomic blocks that would execute fully before the exception
> became visible if it were thrown halfway. If any kind of jumping or
> looping would be disallowed inside an atomic block, the exception
> would eventually be thrown.
>
> I haven't thought this through properly, so maybe there's something
> obvious I'm missing, but it seems logical.

By doing so, you would implicitly stipulate that exceptions can be
thrown asynchronously, meaning that the thread can be interrupted no
matter what it is doing, at any point in time.  This would amount to
rogue termination under the guise of the normalcy of protection, and
rogue termination is possible now.  Even operator new() with its
ubiquity and potential to throw bad_alloc(), provides mechanism for
predictability and order - it will not cause an exception to be thrown
at "any point in time", say, half-way through modifying a global
structure.

If it is required that a thread cannot be interrupted "at any point in
time", but at a "well known check point", then those points would have
to be interspersed in the code everywhere by the compiler to support
expedient cancellation.  If you allow that, one could argue that you
should allow the programmer to use the flag testing technique that John
Q mentioned.  But if you allow flag testing, not only do you have to
keep testing "everywhere", setting up the flag to be tested under each
execution scenario, you essentially implement a
execute-real-code-plus-execute-spin-on-semaphore situation, where
checking the flag involves use of CPU cycles to test the  flag.

And then the problem becomes clear:

The requirement of abrupt termination means that the canceled thread
must not wait too long to check its flag.  But if it is not to wait to
long, that means it must spend much time checking the flag, which is
extremely wasteful, especially in times when it has nothing else to do.
  More importantly in the nothing-else-to-do-but-check-flag situation,
you would have to determine the "optimal" "inter-wait duration" for
checking the "time-to-die" flag.  You will wonder if 1 second is
enough. You will wonder if 5 seconds is enough. You will see that in
certain cases, 100 milliseconds is absolutely positively too much.  And
you will have to have this conversation with yourself each and every
time you use this method.

With events, there is no waste in time, and there is no ambiguity about
"when to check". The thread to be canceled can block indefinitely and
know that it will not have to worry about dying promptly at the behest
of another thread, because triggering of the event by the external
thread will result in immediate unblocking.  You simply right your code
(pun intended), and let the kernel-mode machinery do what it is best
at.

-Le Chaud Lapin-


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Le
1/18/2007 12:13:50 AM
Sergey P. Derevyago wrote:
> Victor Bazarov wrote:
>> What does that mapping accomplish?
>>
> 1. You just divide your task into M parallel jobs. The number of
> jobs doesn't
> depend on the HW you're running.
> 2. You use exactly N threads to process these M jobs. This number N
> depends
> on the HW. You're (the user) supposed to tweak N to obtain the maximum
> possible throughput, possible on _your_ HW.

It still not really an independent "perspective".  It's a combination
of the other two; and since at any point in time it only provides N
threads where N is hardware-dependent, it is actually a variation of
the "1" (create N threads using your hardware as the guide).

The whole point of '2' (where threads are created based upon the tasks
to complete) is that the logic behind the implementation does not
depend on the platform on which it runs.  That's my view of it, anyway.

V
-- 
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Victor
1/18/2007 12:15:07 AM
JohnQ wrote:

> Help me out here, as I don't get it: what do you mean by "map M jobs
> on N CPUs"? What is this "mapping of jobs"? It sounds like option 2
> above to me.

You could probably view it as a special case of option 2 - say you have
two CPUs and six threads, but you mapped/associated the threads such
that you end up with three threads associated with each CPU and the
threads not switching CPUs when they become runnable.

-- 
The lone C++ coder's blog: http://www.bsdninjas.co.uk/codeblog/

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Timo
1/18/2007 12:18:33 AM
JohnQ wrote:
> "Mathias Gaunard" <loufoque@remove.gmail.com> wrote in message
> news:45ad7519$0$30124$426a34cc@news.free.fr...
> >
> > The only way to cancel a thread beautifully is to ask it to stop.
> > For that you can use events, message passing, a shared atomic variable
> > or protected by a mutex...
>
> How do you stop a thread blocking on a socket read call?

Close the socket.  Another approach that works in most multiplexing IO
models is to reserve a socket for in-process communication.  Simply
write a byte to the socket whenever you want to wake up the waiting
thread.  Some models also allow for more direct control.  Windows IO
Completion Ports, for example, provides a routine called
PostQueuedCompletionStatus to signal a specific event.

I think the problem with signalling a waiting thread isn't that it's
complicated so much as that the proper approach depends both on the IO
model and on the application design itself.  And the same goes for
thread termination.  For example, the easiest way to exit a thread
which at least has the potential for being safe is for it to throw
something bizarre like an integer--it's unlikely to be caught by the
application and the stack will be unrolled prior to thread termination.
  In practice, however, I would always favor an application-specific
(ie. cooperative) approach to thread shutdown.


Sean


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Sean
1/18/2007 12:25:18 AM
"red floyd" <no.spam@here.dude> wrote in message
news:yDsrh.21133$yC5.9519@newssvr27.news.prodigy.net...
> JohnQ wrote:
>> "Mathias Gaunard" <loufoque@remove.gmail.com> wrote in message
>> news:45ad7519$0$30124$426a34cc@news.free.fr...
>>> James Kanze wrote:
>>>
>>>>> No one said TerminateThread was being used for "orderly shutdown".
>>>>> Obviously
>>>>> it is "violent" termination of a thread.
>>>> I know.  That's what the documentation says.  So what do you
>>>> use?  I couldn't find anything like pthread_cancel in the
>>>> Microsoft documentation.
>>> The only way to cancel a thread beautifully is to ask it to stop.
>>> For that you can use events, message passing, a shared atomic variable
>>> or protected by a mutex...
>>
>> How do you stop a thread blocking on a socket read call?
>
> Try closing the socket.  The read should then fail.


void SocketThread::Unblock()
{
    // do whatever the platform/api requires to close a socket
}

Sounds reasonable to me. Though I can't actually stop what I'm doing and dig
into old code and start testing sockets/threading. :( I'm not sure how I was
exiting gracefully from blocking sockets calls wrapped in a thread back then
(perhaps I wasn't? I don't see a timeout argument in the socket call of my
API though). Certainly the thought of closing the socket as an unblocking
mechanism has been presented to me for the first time by you here and now.
Sounds reasonable. If in the short term, we need a list of these kinds of
things because the immediate solution is or the common practice is, we
should probably make that list (!). (Dang, I think I just touched upon what
the standardization committee does... go figure! ;) ).

I'm getting some confirmation that my early work of modeling threads (let it
be known that I work in virtual isolation) is sound, or at least is
reasonable compromise/practice. How that will hold up under scrutiny or time
is to be seen. Intuitively, I didn't think too much beyond the need for some
kind of unblocking function, but saw the lack of that as bizarre. Read: yeah
we have threads, but no way to back out of them once they are started! That
thought came to mind right after the cooperative processing era of Windows 3
when it transitioned to a preemptive model. I kept some of the cooperative
concepts as still valid. The "looping thread" for example. It's from the
"cooperative processing" model: you have the opportunity at distinct points
to do something, namely, once every iteration through the loop (like exiting
the thread gracefully in response to a set flag, probably NOT an "event" if
avoidable). I'm "in the box" right now about overall thread framework
architecture/design because I see certain mechanisms as adequate, but it
they may not be "generally". If it works for any application program today,
I'm satisfied in using the concept (of having a program/api-specific
unblocking function for example).

John


--
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
JohnQ
1/18/2007 9:42:43 AM
"PeteK" <pete_k_1955@yahoo.co.uk> wrote in message
news:1169052415.094119.248500@s34g2000cwa.googlegroups.com...
> JohnQ wrote:
>> "Le Chaud Lapin" <jaibuduvin@gmail.com> wrote in message
>> news:1168971030.975857.16630@q2g2000cwa.googlegroups.com...
>> > Yechezkel Mett wrote:
>> >> James Kanze wrote:
>> >> > JohnQ wrote:
>> >> >> No one said TerminateThread was being used for "orderly shutdown".
>> >> Obviously
>> >> >> it is "violent" termination of a thread.
>> >> >
>> >> > I know.  That's what the documentation says.  So what do you
>> >> > use?  I couldn't find anything like pthread_cancel in the
>> >> > Microsoft documentation.
>> >>
>> >> You use a "shutdown" event, and every blocking operation in the thread
>> >> uses WaitForMultipleObjects with the shutdown event as one of the
>> >> objects.
>> >
>> > :)
>>
>> That sounded like a good idea, but how will it solve THE problem of a
>> blocking socket read, for example, since you can't wait on the read
>> function
>> and an event both with WaitForMultipleObjects?
>>
>
> This is getting somewhat off topic, but since you asked ...
>
> It's been a long time since I wrote any Windows socket stuff, but there
> used to be a function something like WSACancelBlockingCall.

Yes! 'used to be' being the KEY words.

> These days
> you'd probably use overlapped I/O and WaitForMultipleEvents.

"defeats the purpose". The whole concept of wrapping blocking socket calls
in threads was to avoid proprietary interfaces. (At least, that's why I
built upon BSD blocking sockets). Asynchronous Windows sockets were too much
to accept at low levels of development. (Has it really been 10+ years?! :().

John

(P.S. To mods: not off topic at all IMO, since standardization work about
threads/threading/MT is still evolving, but at an even higher level, is
constantly "battling" language-proper vs. library vs. std library issues, I
find this topic not only engaging but VERY relevant. My .02. Please post my
..02).


John


--
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
JohnQ
1/18/2007 9:46:25 AM
JohnQ wrote:

>>It depends on the application.  You generally will not tolerate
>>the loss of responsivity just because one or two clients are
>>performing extremely complex requests.
>
> OK, you're thinking SQL server and I'm thinking OLTP server.

Somehow this subthread went soooo far off a tangent!!  :-)

My initial point was simple:  provided that you decide that you
want multiple threads (given the way you decide your software
design goes), then the rule concerning how many threads (or
rather, whether or not more threads than available CPU cores)
is simple:

If the task involved (in this case, database processing) involves
a non-negligible fraction of tasks that are IO-bound, such as
reading or writing the disk, sending or receiving through the
network, or any other tasks that block the CPU into an idle
state of doing nothing while waiting for some event to happen
or to be completed, *then*, having more active threads than
available CPUs is bound to improve performance, responsiveness,
etc.

That's the main issue:  if part of the processing involves
writing to the disk, then of course we want to have more
active threads, so that *they* can take advantage of using
the processor while this thread waits for the disk writing
to be completed --- otherwise, you would have completely
wasted that time.

When the task does not involve *at all* any IO operations,
then there is no point in having more active threads, since
the total amount of time used for the computations will be
the same, but then we'd add the thread-switch overhead and
other nasties.

Therefore, my initial assessment/estimate:  for a database
server, it *must* make sense having more active threads than
available CPU cores;  a database (that it is SQL, OLTP,
or whatever that deals with information on the disk) server
necessarily has a considerable fraction of the processing
that involves writing to the disk --- really, it doesn't
matter how you look at it:  the database server will be
spending time writing to the disk;  having additional active
threads that would take advantage of that idle time will
improve performance.

Carlos
--

--
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Carlos
1/18/2007 9:47:58 AM
Victor Bazarov wrote:
> It still not really an independent "perspective".  It's a combination
> of the other two;
>
	Yes, that's the point.
	We're not obliged to choose only one alternative. We can combine the
best
properties of two.
--
         With all respect, Sergey.               http://ders.stml.net/
         mailto : ders at skeptik.net

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Sergey
1/18/2007 5:50:00 PM
{ we seem to have changed tracks here.  please bring it closer to
  discussing C++, if possible.  thanks.  -mod }

JohnQ wrote:
>> The only way to cancel a thread beautifully is to ask it to stop.
>> For that you can use events, message passing, a shared atomic variable
>> or protected by a mutex...
> 
> How do you stop a thread blocking on a socket read call?

Use some form of socket io which doesn't block, such as POSIX aio, 
Windows overlapped io, or select (or equivalent) followed by a 
read/write with the socket set to non-blocking.

The thing about WaitForMultipleObjects, and a way in which it differs 
from select, is that a successful wait on an object often also changes 
the state of an object. For example, successfully waiting on a mutex 
takes the mutex. In some cases however, it is better to think of it as 
simply notifying you that you may be able to use the object and then 
attempting the use (e.g. read or write) afterwards.

Yechezkel Mett

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Yechezkel
1/18/2007 5:53:22 PM
Carlos Moreno wrote:
> JohnQ wrote:

> >>It depends on the application.  You generally will not tolerate
> >>the loss of responsivity just because one or two clients are
> >>performing extremely complex requests.

> > OK, you're thinking SQL server and I'm thinking OLTP server.

> Somehow this subthread went soooo far off a tangent!!  :-)

That seems to be the status of a number of threads at the
moment:-).

> My initial point was simple:  provided that you decide that you
> want multiple threads (given the way you decide your software
> design goes), then the rule concerning how many threads (or
> rather, whether or not more threads than available CPU cores)
> is simple:

> If the task involved (in this case, database processing) involves
> a non-negligible fraction of tasks that are IO-bound, such as
> reading or writing the disk, sending or receiving through the
> network, or any other tasks that block the CPU into an idle
> state of doing nothing while waiting for some event to happen
> or to be completed, *then*, having more active threads than
> available CPUs is bound to improve performance, responsiveness,
> etc.

And the point of my posting (to which JohnQ was responding) is
that there can be other reasons to use more threads, such as
responsiveness.  I write large scale servers for a
living---on-line transaction systems, if you want a buzz word,
but I was writing them well before the acronym existed.  Some of
the requests the server receives may require extensive CPU time
(up to five minutes); one of the motivations for threading is
(or was---when the system was designed, we only had a single
processor system) to ensure responsiveness for the simple
requests: if a simple request occurs during the processing of a
long request, it will still get treated, without waiting for the
long request to terminate.

This does increase the total CPU load, because of the added time
for context swapping, etc.  But that's not the issue here; most
of the time, the server isn't doing anything anyway.  The
important point is that a user who makes a simple request gets a
fast answer, regardless of what other users might be doing at
the time.

      [BTW: I've put follow-ups to comp.programming.threads.  This
    really has nothing to do with C++.]

--
James Kanze (GABI Software)             email:james.kanze@gmail.com
Conseils en informatique orientie objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place Simard, 78210 St.-Cyr-l'Icole, France, +33 (0)1 30 23 00 34


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
James
1/18/2007 5:54:24 PM
Le Chaud Lapin wrote:
> Lourens Veen wrote:
> > Why not use C++' exception mechanism to cancel threads? The owner of a
> > thread object (or handle or reference or whatever) calls a cancel()
> > function which causes a thread_cancelled exception to be thrown in
> > that thread. Then cleanup can happen by the normal exception
> > handlers.

> > It seems from a quick web search that this idea is obvious enough that
> > it's been at least tried before. I can see a problem with throw()
> > declarations becoming somewhat less of a guarantee, and there would
> > have to be a very careful specification of at which points the
> > exception would become visible. Perhaps it would even be useful to
> > have atomic blocks that would execute fully before the exception
> > became visible if it were thrown halfway. If any kind of jumping or
> > looping would be disallowed inside an atomic block, the exception
> > would eventually be thrown.

> > I haven't thought this through properly, so maybe there's something
> > obvious I'm missing, but it seems logical.

> By doing so, you would implicitly stipulate that exceptions can be
> thrown asynchronously, meaning that the thread can be interrupted no
> matter what it is doing, at any point in time.

That's not necessarily implementable.  Depending on how the
compiler generates function prologues, there could easily be
instances where a stack walkback would be simply impossible.

Lourens may be referring to the text in the rationale section of
Posix specification of pthread_cleanup_push and
pthread_cleanup_pop: "Note that the specified cleanup handling
mechanism is especially tied to the C language and, while the
requirement for a uniform mechanism for expressing cleanup is
language-independent, the mechanism used in other languages may
be quite different. In addition, this mechanism is really only
necessary due to the lack of a real exception mechanism in the C
language, which would be the ideal solution."  The last sentence
is particularly interesting in a C++ context (but I know of no
C++ compiler at present which gives you a catchable exception
when a thread is cancelled).  Note, however, that cancellation
under Posix is not normally asynchronous; the Posix standard
defines a certain number of cancellation points, and the
cancellation will be deferred until the thread to be cancelled
is at one of these points.  (Note that all potentially blocking
requests, like read(), recv(), or pthread_cond_wait()---but not
pthread_mutex_wait()!---are cancellation points.  There is also
a request pthread_testcancel() which does nothing except create
a cancellation point.)

Note that with g++, thread cancellation does NOT call the
destructors of local objects in the thread.  Which means that
for all practical purposes, it cannot be used.

> This would amount to
> rogue termination under the guise of the normalcy of protection, and
> rogue termination is possible now.  Even operator new() with its
> ubiquity and potential to throw bad_alloc(), provides mechanism for
> predictability and order - it will not cause an exception to be thrown
> at "any point in time", say, half-way through modifying a global
> structure.

Correct.  This is very, very important.  You can't allow fully
asynchronous termination and expect to get a working program.

> If it is required that a thread cannot be interrupted "at any point in
> time", but at a "well known check point", then those points would have
> to be interspersed in the code everywhere by the compiler to support
> expedient cancellation.  If you allow that, one could argue that you
> should allow the programmer to use the flag testing technique that John
> Q mentioned.  But if you allow flag testing, not only do you have to
> keep testing "everywhere", setting up the flag to be tested under each
> execution scenario, you essentially implement a
> execute-real-code-plus-execute-spin-on-semaphore situation, where
> checking the flag involves use of CPU cycles to test the  flag.

That's not the real problem.  The real problem is that you
cannot test the flag when you're blocked, say reading a socket.
The standard solution is to use a time-out on the read, and poll
the flag whenever the time-out expires.  (Another solution, at
least under Unix, is to create a pipe and associate it with such
flags; anytime you modify the flag, you then write a byte in the
pipe, and any thread interested in the flag will add the pipe to
its list of devices waited for in the select.)

> And then the problem becomes clear:

> The requirement of abrupt termination means that the canceled thread
> must not wait too long to check its flag.  But if it is not to wait to
> long, that means it must spend much time checking the flag, which is
> extremely wasteful, especially in times when it has nothing else to do.

It's even more wasteful when the thread has real work to do.
Still, in practice, if we're talking about clean shut-down,
checking the flag once a second is typically sufficient, and it
shouldn't take more than a couple of microseconds to check.  So
it shouldn't be a serious problem unless we have a couple of
thousand threads checking.

>   More importantly in the nothing-else-to-do-but-check-flag situation,
> you would have to determine the "optimal" "inter-wait duration" for
> checking the "time-to-die" flag.  You will wonder if 1 second is
> enough. You will wonder if 5 seconds is enough. You will see that in
> certain cases, 100 milliseconds is absolutely positively too much.  And
> you will have to have this conversation with yourself each and every
> time you use this method.

> With events, there is no waste in time, and there is no ambiguity about
> "when to check". The thread to be canceled can block indefinitely and
> know that it will not have to worry about dying promptly at the behest
> of another thread, because triggering of the event by the external
> thread will result in immediate unblocking.  You simply right your code
> (pun intended), and let the kernel-mode machinery do what it is best
> at.

How does this solve the problem of having to check when you're
doing intensive CPU?  You still have to poll from time to time.

--
James Kanze (GABI Software)             email:james.kanze@gmail.com
Conseils en informatique orientie objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place Simard, 78210 St.-Cyr-l'Icole, France, +33 (0)1 30 23 00 34


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
James
1/18/2007 5:56:47 PM
Sergey P. Derevyago wrote:
> Victor Bazarov wrote:
>> It still not really an independent "perspective".  It's a combination
>> of the other two;
>>
> Yes, that's the point.

... And you just trimmed away the actual point.  Right there after the
semicolon which you've left in I say <<and since at any point in time
it only provides N threads where N is hardware-dependent, it is
actually a variation of the "1">>.

> We're not obliged to choose only one alternative. We can combine the
> best
> properties of two.

But you _do_ choose the "1" (in your terms).  Don't you actually see
it yourself?

Peter Becker wrote:
====
There are two different perspectives on multi-threaded
programming. On is "distribute the workload optimally among the
available processors." That's when you want just as many threads as
processor cores. The other is "logically divide the process into tasks
that can be run concurrently." That's when you want as many threads as
appropriate, and are willing to put up with some thrashing and delays
when you have more threads than cores.
====

The fact that you subdivide your processing into M tasks is irrelevant
because right after that you "map" them into 'N' simultaneous threads
based on the available hardware.  So, the number of actual threads
running is governed by the hardware.

THAT'S the point.

V
-- 
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Victor
1/18/2007 9:48:58 PM
James Kanze wrote:

> Le Chaud Lapin wrote:
>> Lourens Veen wrote:
>> > Why not use C++' exception mechanism to cancel threads? The owner
>> > of a thread object (or handle or reference or whatever) calls a
>> > cancel() function which causes a thread_cancelled exception to be
>> > thrown in that thread. Then cleanup can happen by the normal
>> > exception handlers.
> 
>> > It seems from a quick web search that this idea is obvious enough
>> > that it's been at least tried before. I can see a problem with
>> > throw() declarations becoming somewhat less of a guarantee, and
>> > there would have to be a very careful specification of at which
>> > points the exception would become visible. Perhaps it would even
>> > be useful to have atomic blocks that would execute fully before
>> > the exception became visible if it were thrown halfway. If any
>> > kind of jumping or looping would be disallowed inside an atomic
>> > block, the exception would eventually be thrown.
> 
>> > I haven't thought this through properly, so maybe there's
>> > something obvious I'm missing, but it seems logical.
> 
>> By doing so, you would implicitly stipulate that exceptions can be
>> thrown asynchronously, meaning that the thread can be interrupted
>> no matter what it is doing, at any point in time.

No, I said that there would have to be a very careful specification of
at which points the exception would become visible. Meaning that the
standard would give some very specific points where it could be
interrupted, at specific points in time.

> That's not necessarily implementable.  Depending on how the
> compiler generates function prologues, there could easily be
> instances where a stack walkback would be simply impossible.
> 
> Lourens may be referring to the text in the rationale section of
> Posix specification of pthread_cleanup_push and
> pthread_cleanup_pop:

Actually, I've never read the Posix spec itself, so no, but it's nice
to see that there are people who didn't think this a crazy idea in
itself :).

> the Posix standard
> defines a certain number of cancellation points, and the
> cancellation will be deferred until the thread to be cancelled
> is at one of these points.  (Note that all potentially blocking
> requests, like read(), recv(), or pthread_cond_wait()---but not
> pthread_mutex_wait()!---are cancellation points.  There is also
> a request pthread_testcancel() which does nothing except create
> a cancellation point.)

However, something like that _is_ what I was thinking of. Perhaps with
some more cancellation points thrown in automatically to avoid having
to place explicit ones everywhere. But like I said, I haven't thought
it through, so I have no specific proposals.

Lourens


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Lourens
1/19/2007 6:26:15 AM
Victor Bazarov wrote:
> But you _do_ choose the "1" (in your terms).  Don't you actually see
> it yourself?
>
> Peter Becker wrote:
> ====
> There are two different perspectives on multi-threaded
> programming. On is "distribute the workload optimally among the
> available processors." That's when you want just as many threads as
> processor cores. The other is "logically divide the process into tasks
> that can be run concurrently." That's when you want as many threads as
> appropriate, and are willing to put up with some thrashing and delays
> when you have more threads than cores.
> ====
>
> The fact that you subdivide your processing into M tasks is irrelevant
> because right after that you "map" them into 'N' simultaneous threads
> based on the available hardware.  So, the number of actual threads
> running is governed by the hardware.
>
> THAT'S the point.
>
        Not, really.
        It was stated that we have (only) two perspectives:
        (2). "Logically divide the process into tasks that can be run
concurrently"
and do YYY.
        (1). Do XXX.
        As you see, the (1) alternative doesn't mean that you can
"logically divide
the process into tasks that can be run concurrently".

        What actually was stated is:
1. Count your processors but do NOT "divide the process into tasks that can be
run concurrently".
2. "Divide the process into tasks that can be run concurrently" and start as
many threads as you can.

        I proposed the combination: Divide the process into jobs that can be run
concurrently and allow any user to set fixed number of threads that will be
used to process these jobs on his particular HW.
        Another user can (empirically) choose another number of threads but the
number of parallel tasks was already set by your program design from the very
beginning.
--
         With all respect, Sergey.               http://ders.stml.net/
         mailto : ders at skeptik.net

--
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Sergey
1/19/2007 1:08:06 PM
Lourens Veen wrote:
> James Kanze wrote:

      [...]
> > the Posix standard
> > defines a certain number of cancellation points, and the
> > cancellation will be deferred until the thread to be cancelled
> > is at one of these points.  (Note that all potentially blocking
> > requests, like read(), recv(), or pthread_cond_wait()---but not
> > pthread_mutex_wait()!---are cancellation points.  There is also
> > a request pthread_testcancel() which does nothing except create
> > a cancellation point.)

> However, something like that _is_ what I was thinking of. Perhaps with
> some more cancellation points thrown in automatically to avoid having
> to place explicit ones everywhere. But like I said, I haven't thought
> it through, so I have no specific proposals.

I know that some of the members of the committee are discussing
such things, but I'm not up to date on their discussions.  In
general, however, there are some differences between
cancellation and exceptions.  To be really useful, C++
cancellation more or less has to propagate up to the top; you
don't want to allow catching it, and retrying the operation, for
example.  What you'd probably want (just guessing a little) is:

 -- the type thrown doesn't have a namable name, so cannot be
    caught except with "catch (...)", and

 -- exiting the catch block causes it to automatically be
    rethrown.

That second point is definitly different from normal exception
semantics.

Another possibility is to do what current Sun CC does: it
unwinds the stack, calling destructors, but does NOT enter catch
blocks.  This, too, introduces something new: the RAII idiom has
different semantics than a catch (and in fact, in many cases,
becomes required).

Finally, I don't think it's implementable under Windows.  (But I
could easily be wrong there---I don't know Windows very well.)

--
James Kanze (GABI Software)             email:james.kanze@gmail.com
Conseils en informatique orientie objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place Simard, 78210 St.-Cyr-l'Icole, France, +33 (0)1 30 23 00 34


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
James
1/19/2007 4:21:29 PM
"James Kanze" <james.kanze@gmail.com> wrote in message 
news:1169116594.820798.273880@38g2000cwa.googlegroups.com...
> Carlos Moreno wrote:
>> JohnQ wrote:
>
>> >>It depends on the application.  You generally will not tolerate
>> >>the loss of responsivity just because one or two clients are
>> >>performing extremely complex requests.
>
>> > OK, you're thinking SQL server and I'm thinking OLTP server.
>
>> Somehow this subthread went soooo far off a tangent!!  :-)
>
> That seems to be the status of a number of threads at the
> moment:-).
>
>> My initial point was simple:  provided that you decide that you
>> want multiple threads (given the way you decide your software
>> design goes), then the rule concerning how many threads (or
>> rather, whether or not more threads than available CPU cores)
>> is simple:
>
>> If the task involved (in this case, database processing) involves
>> a non-negligible fraction of tasks that are IO-bound, such as
>> reading or writing the disk, sending or receiving through the
>> network, or any other tasks that block the CPU into an idle
>> state of doing nothing while waiting for some event to happen
>> or to be completed, *then*, having more active threads than
>> available CPUs is bound to improve performance, responsiveness,
>> etc.
>
> And the point of my posting (to which JohnQ was responding) is
> that there can be other reasons to use more threads, such as
> responsiveness.  I write large scale servers for a
> living---on-line transaction systems, if you want a buzz word,
> but I was writing them well before the acronym existed.  Some of
> the requests the server receives may require extensive CPU time
> (up to five minutes); one of the motivations for threading is
> (or was---when the system was designed, we only had a single
> processor system) to ensure responsiveness for the simple
> requests: if a simple request occurs during the processing of a
> long request, it will still get treated, without waiting for the
> long request to terminate.
>
> This does increase the total CPU load, because of the added time
> for context swapping, etc.  But that's not the issue here; most
> of the time, the server isn't doing anything anyway.  The
> important point is that a user who makes a simple request gets a
> fast answer, regardless of what other users might be doing at
> the time.

My perspective was from building a database, say a special purpose embedded 
transactional DB,  rather than using one.

John 


0
JohnQ
1/19/2007 7:45:22 PM
[ to the moderator: I apologize for dragging this less-than-topical
  discussion so long.  this is my last posting in support of Peter
  Becker's original argument. ]

Sergey P. Derevyago wrote:
> Victor Bazarov wrote:
>> But you _do_ choose the "1" (in your terms).  Don't you actually see
>> it yourself?
>>
>> Peter Becker wrote:
>> ====
>> There are two different perspectives on multi-threaded
>> programming. On is "distribute the workload optimally among the
>> available processors." That's when you want just as many threads as
>> processor cores. The other is "logically divide the process into
>> tasks that can be run concurrently." That's when you want as many
>> threads as appropriate, and are willing to put up with some
>> thrashing and delays when you have more threads than cores.
>> ====
>>
>> The fact that you subdivide your processing into M tasks is
>> irrelevant because right after that you "map" them into 'N'
>> simultaneous threads based on the available hardware.  So, the
>> number of actual threads running is governed by the hardware.
>>
>> THAT'S the point.
>>
>        Not, really.
>        It was stated that we have (only) two perspectives:
>        (2). "Logically divide the process into tasks that can be run
> concurrently"
> and do YYY.
>        (1). Do XXX.
>        As you see, the (1) alternative doesn't mean that you can
> "logically divide
> the process into tasks that can be run concurrently".

Huh?  Where do you get this YYY and XXX from?  The quote from Peter
Becker is right there.  Is the "XXX" you use the actual "distribute
the work load among the available processors"?  What "YYY"?

You don't have to answer.  I just mean to point out the weakness
of such method of "interpreting" other statements.

>
>        What actually was stated is:

"Was stated" by whom?  Is this your interpretation of somebody else's
words or is that your own thoughts?  Are you referring to Peter's
statements or someone elses?  Please clarify next time.

> 1. Count your processors but do NOT "divide the process into tasks
> that can be run concurrently".

How can you NOT divide if the whole point is to come up with a set
of threads that perform some operations relatively independently?

> 2. "Divide the process into tasks that can be run concurrently" and
> start as many threads as you can.
>
>        I proposed the combination: Divide the process into jobs that
> can be run concurrently and allow any user to set fixed number of
> threads that will be used to process these jobs on his particular HW.
>        Another user can (empirically) choose another number of
> threads but the number of parallel tasks was already set by your
> program design from the very beginning.

I understand that it can be difficult to admit a mistake.  I admit my
mistake of getting into this "debate".  It seems to have no resolution
in sight.

But here is one more, my last, attempt.

The splitting your program into threads has the goal that is _always_
"divide the process into tasks that can be run concurrently".  There
can be no debate about this, it's the definition of a thread.  A task
can be "to perform some percentage of calculations" or it can be "to
clean the database" or "to collect garbage".  The difference is what
you use as the *defining* criterion for your splitting.

The "perform some portion of lengthy iterative work where iterations
don't depend on each other" variation, for example, falls under (1) and
the number of cores is the criterion.  In that case the decision does
not involve the nature (so to speak) of the task, it only involves the
_amount of work_ to be done.  This is what scientific simulations often
do on multi-processor systems.

"Collect this", "clean that", "refresh something", all fall under (2)
and the *defining* criterion is the nature (so to speak) of the task
to be performed.  This is more common in complex systems where the
types of processing jobs is too different to identify "percentages".

In all cases there has to be relative independence of the tasks to
justify their running in parallel.

The main difference between (1) and (2) is that (1) has *hardware* as
the defining criterion and (2) does NOT.  So, whenever you involve
hardware (whether your program decides how to split the work, or the
user) it falls under (1).  Period.  Whether the "all the work" does
actually consist of "'M' tasks to be performed independently" matters
not.  As soon as you say "I have some amount of work to do, let's
start N threads because I have K cores", it's (1).  If you happen to
say "I have L independent jobs to do, I'll start L threads and let
the system decide how to execute them optimally", it's (2).

That's all I have to say.  Thank you for reading.

V
-- 
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask 



      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Victor
1/19/2007 10:18:21 PM
"Carlos Moreno" <moreno_at_mochima_dot_com@mailinator.com> wrote in message 
news:Vfzrh.159692$jk2.2389961@wagner.videotron.net...
> JohnQ wrote:
>
>>>It depends on the application.  You generally will not tolerate
>>>the loss of responsivity just because one or two clients are
>>>performing extremely complex requests.
>>
>> OK, you're thinking SQL server and I'm thinking OLTP server.
>
> Somehow this subthread went soooo far off a tangent!!  :-)
>
> My initial point was simple:  provided that you decide that you
> want multiple threads (given the way you decide your software
> design goes), then the rule concerning how many threads (or
> rather, whether or not more threads than available CPU cores)
> is simple:
>
> If the task involved (in this case, database processing) involves
> a non-negligible fraction of tasks that are IO-bound, such as
> reading or writing the disk, sending or receiving through the
> network, or any other tasks that block the CPU into an idle
> state of doing nothing while waiting for some event to happen
> or to be completed, *then*, having more active threads than
> available CPUs is bound to improve performance, responsiveness,
> etc.

Not necessarily because chances are the contention for the IO will continue 
so processing performance increase only in the short term until caches and 
things fill up. If you just keep spawning more threads, you end up 
thrashing.

> That's the main issue:  if part of the processing involves
> writing to the disk, then of course we want to have more
> active threads, so that *they* can take advantage of using
> the processor while this thread waits for the disk writing
> to be completed --- otherwise, you would have completely
> wasted that time.

If you have 100 transactions queued up that will need the disk, then they 
can only proceed as fast as the disk can perform if that is the bottleneck.

> When the task does not involve *at all* any IO operations,
> then there is no point in having more active threads, since
> the total amount of time used for the computations will be
> the same, but then we'd add the thread-switch overhead and
> other nasties.
>
> Therefore, my initial assessment/estimate:  for a database
> server, it *must* make sense having more active threads than
> available CPU cores;  a database (that it is SQL, OLTP,
> or whatever that deals with information on the disk) server
> necessarily has a considerable fraction of the processing
> that involves writing to the disk --- really, it doesn't
> matter how you look at it:  the database server will be
> spending time writing to the disk;  having additional active
> threads that would take advantage of that idle time will
> improve performance.

Not necessarily. If every transaction requires a disk write, for example, 
then those transactions will only complete as fast as the disk can write 
assuming the disk is a bottleneck.

John 


-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
JohnQ
1/19/2007 10:38:47 PM
Victor Bazarov wrote:
> [ to the moderator: I apologize for dragging this less-than-topical
>   discussion so long.  this is my last posting in support of Peter
>   Becker's original argument. ]
>
        I also see no point to continue this subthread.
        What's going on is: we agree in what Peter Becker has written, but disagree
in how to interpret his words. As long as there exists certain
misunderstanding, we can agree that the original statement wasn't enough
clear.

> The splitting your program into threads has the goal that is _always_
> "divide the process into tasks that can be run concurrently".
>
        The devil is in the details.
        Please visit "The C10K problem" web page http://www.kegel.com/c10k.html to
understand the necessary details.
--
         With all respect, Sergey.               http://ders.stml.net/
         mailto : ders at skeptik.net

-- 
      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Sergey
1/22/2007 8:57:10 PM
Reply: