Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

many semaphores

4 views
Skip to first unread message

Vu Pham

unread,
May 7, 2002, 2:53:10 PM5/7/02
to
Hi all,

My problem is :
A Linux host communicates with N mobile devices ( N is about 150 - 200
). My current implementation uses two threads InThread and OutThread
to handle incoming and outcoming packets at the lowest level. I need
to implement the sliding window so that, for each device, there will
no be more than K packets sending from host that are not acknowledged
by that device.

My plan is to create N semaphores with initial value of each
semaphores being K. Inthread will sem_post the semaphore of the
correspoding device. OutThread will sem_wait on the semaphore of the
corresponding device.

The idea of having separate semaphore for each deivce is to prevent
the case that InThread for data of device A blocks OutThread for data
of device B.

Is there any reason not to create so many semaphores ( resource,
performance, ... ) ?

Some other factors:
- the host will never send more than 10 packets/second
- the host is a Linux box kernel 2.4.9 with 256 Mb.
- currently it serves around 45 devices pretty well

Thanks for your advice,

Vu

Joe Seigh

unread,
May 8, 2002, 5:16:31 AM5/8/02
to

Vu Pham wrote:
>
> Hi all,
>
> My problem is :
> A Linux host communicates with N mobile devices ( N is about 150 - 200
> ). My current implementation uses two threads InThread and OutThread
> to handle incoming and outcoming packets at the lowest level. I need
> to implement the sliding window so that, for each device, there will
> no be more than K packets sending from host that are not acknowledged
> by that device.
>
> My plan is to create N semaphores with initial value of each
> semaphores being K. Inthread will sem_post the semaphore of the
> correspoding device. OutThread will sem_wait on the semaphore of the
> corresponding device.
>
> The idea of having separate semaphore for each deivce is to prevent
> the case that InThread for data of device A blocks OutThread for data
> of device B.

I think you ended up guaranteeing it instead. If OutThread is blocked
on device A then it cannot process device B no matter how ready it is.

>
> Is there any reason not to create so many semaphores ( resource,
> performance, ... ) ?
>

In this case, 1 is too many. Semaphores are inappropiate to the solution
of this problem. Try a condition variable in conjunction with some
data structure or something. Otherwise you risk becoming a poster child
for why semaphores are a Bad Thing.

Joe Seigh

Vu Pham

unread,
May 9, 2002, 9:07:21 AM5/9/02
to
Joe Seigh <jse...@genuity.com> wrote in message
[...]

> > The idea of having separate semaphore for each deivce is to prevent
> > the case that InThread for data of device A blocks OutThread for data
> > of device B.
>
> I think you ended up guaranteeing it instead. If OutThread is blocked
> on device A then it cannot process device B no matter how ready it is.
Yes, if OutThread is busy with a device A, it will not process other
devices. But at least it will when InThread processes a device != A.


> >
> > Is there any reason not to create so many semaphores ( resource,
> > performance, ... ) ?
> >
> In this case, 1 is too many. Semaphores are inappropiate to the solution
> of this problem. Try a condition variable in conjunction with some
> data structure or something. Otherwise you risk becoming a poster child
> for why semaphores are a Bad Thing.

Thanks. I found one case that semaphore is not good for this problem
when there are lost packets, and now I am using mutex to control the
access. But besides the inappropriate logic in this problem, would you
please explain me why using many semaphores are not very good ? How
about multiple mutex ?

Thanks,

Vu

Joe Seigh

unread,
May 10, 2002, 6:45:51 AM5/10/02
to

Vu Pham wrote:
>
> Joe Seigh <jse...@genuity.com> wrote in message
> [...]
> > > The idea of having separate semaphore for each deivce is to prevent
> > > the case that InThread for data of device A blocks OutThread for data
> > > of device B.
> >
> > I think you ended up guaranteeing it instead. If OutThread is blocked
> > on device A then it cannot process device B no matter how ready it is.
> Yes, if OutThread is busy with a device A, it will not process other
> devices. But at least it will when InThread processes a device != A.

Yes, but do you want OutThread to not process any ready devices until
an ack is received on device A no matter how long that takes and no
matter how much work is pending for devices that are ready?


>
> > >
> > > Is there any reason not to create so many semaphores ( resource,
> > > performance, ... ) ?
> > >
> > In this case, 1 is too many. Semaphores are inappropiate to the solution
> > of this problem. Try a condition variable in conjunction with some
> > data structure or something. Otherwise you risk becoming a poster child
> > for why semaphores are a Bad Thing.
>
> Thanks. I found one case that semaphore is not good for this problem
> when there are lost packets, and now I am using mutex to control the
> access. But besides the inappropriate logic in this problem, would you
> please explain me why using many semaphores are not very good ? How
> about multiple mutex ?
>

The semaphore "solution" doesn't really apply cleanly to anything, not
even the fabled single producer / single consumer problem. Unless of
course you never want to shut it down. If you did want it to shut
down you could add a flag and check it after the sem_wait(). Kludgey,
but not too horribly kludgey. But you don't get clean shutdown that
way, just abort shutdown since you don't know whether you've processed
all the buffers or not, not without some really kludgey logic.

If you deconstruct the XRAT (design rationalization) for semaphores,
you can surmise that somebody thought that semaphores could be
implemented that more efficient than condition variables, and so
it might be useful to have that efficiency in case it could be
exploited. Semaphore are certainly not necessary. You can get
along fine without them.

You should do your design using the more general mechanism, condition
variables, and then, if it lends itself to a semaphore solution without
too much contortion, and if the semaphore implementation actually is
in fact significantly more efficient, and if performance really is that
much of a critical issue, then by all means, go ahead and use semaphores.

In the case of your problem a solution would be use some sort of data
structure, set, queue, priority queue, or whatever, to communicate to
OutThread which devices were ready to communicate with. You may be
using more than one mutex since there is the data structure itself
and data associated with each device such as a count.

So OutThread logic is going to look something like

while (outbound data) {
while (ready devices) {
...
}
}

which translated into CV logic

while (outbound data) {
pthread_mutex_lock();
while (no ready devices) {
pthread_cond_wait();
}
...
pthread_mutex_unlock();
...
}

Joe Seigh

Alexander Terekhov

unread,
May 10, 2002, 10:11:39 AM5/10/02
to

Vu Pham wrote:
[...]

> But besides the inappropriate logic in this problem, would you
> please explain me why using many semaphores are not very good ?

http://www.opengroup.org/onlinepubs/007904975/xrat/xsh_chap02.html#tag_03_02_08_03
(please pay attention to "Much experience with semaphores shows...",
"With respect to binary semaphores, experience has shown..." and
".......It is for these reasons that IEEE Std 1003.1-2001 allows
semaphores to be used by threads. .... Mutexes and condition
variables together constitute an appropriate, sufficient, and
complete set of inter-thread synchronization primitives.")

Also:

http://groups.google.com/groups?selm=c29b5e33.0201310709.3ffc3476%40posting.google.com
(Subject: Re: mutex or semaphores?)

regards,
alexander.

t...@cs.ucr.edu

unread,
May 19, 2002, 1:03:37 PM5/19/02
to
Alexander Terekhov <tere...@web.de> wrote:

: Vu Pham wrote:
: [...]
:> But besides the inappropriate logic in this problem, would you
:> please explain me why using many semaphores are not very good ?

: http://www.opengroup.org/onlinepubs/007904975/xrat/xsh_chap02.html#tag_03_02_08_03
: (please pay attention to "Much experience with semaphores shows...",
: "With respect to binary semaphores, experience has shown..." and
: ".......It is for these reasons that IEEE Std 1003.1-2001 allows
: semaphores to be used by threads. .... Mutexes and condition
: variables together constitute an appropriate, sufficient, and
: complete set of inter-thread synchronization primitives.")

The standard analogy is that semphores are to concurent programming
what goto's are to sequential programming. They are efficient and
general purpose, but lead to ill-structured solutions. Also, they do
not generalize gracefully to timed and/or prioritized waiting.

Tom Payne


Alexander Terekhov

unread,
May 21, 2002, 7:03:25 AM5/21/02
to

Daniel Miller

unread,
May 21, 2002, 5:57:24 PM5/21/02
to
Alexander Terekhov wrote:

> t...@cs.ucr.edu wrote:
>
>>Alexander Terekhov <tere...@web.de> wrote:
>>
>>: Vu Pham wrote:
>>: [...]
>>:> But besides the inappropriate logic in this problem, would you
>>:> please explain me why using many semaphores are not very good ?
>>
>>: http://www.opengroup.org/onlinepubs/007904975/xrat/xsh_chap02.html#tag_03_02_08_03
>>: (please pay attention to "Much experience with semaphores shows...",
>>: "With respect to binary semaphores, experience has shown..." and
>>: ".......It is for these reasons that IEEE Std 1003.1-2001 allows
>>: semaphores to be used by threads. .... Mutexes and condition
>>: variables together constitute an appropriate, sufficient, and
>>: complete set of inter-thread synchronization primitives.")
>>
>>The standard analogy is that semphores are to concurent programming
>>what goto's are to sequential programming. They are efficient and
>>general purpose, but lead to ill-structured solutions.


Many engineers in realtime embedded systems have used semaphores successfully
for decades. Semaphores are an integral lucid portion of two very successful
and very widely deployed time-honored idioms: (multi)producer-(multi)consumer
and pool-dispenser. See
http://groups.google.com/groups?q=Daniel+Miller+group:comp.programming.threads&hl=en&lr=&selm=3CD1864A.10401%40tellabs.com&rnum=3


> Agreed with "but lead to illness", but I disagree strongly
> with both "like goto" -- semas are *much worse* than "goto",
> and "efficient/general purpose" -- they are neither efficient
> nor general purpose; mutexes PLUS condvars *ARE* efficient
> and general purpose, though. ;-)


I find it ironic that anti-goto and anti-semaphore statements are uttered in
the same breath (so to speak) and by two different people no less. The 1)
progenitor of the original goto-critique statements which have (somewhat
inadvertently) precipitated a worldwide disdain for goto is the 2) very same
inventor of semaphores: Dr Edsger Wybe Dijkstra.

http://www.cs.utexas.edu/users/UTCS/report/1994/profiles/dijkstra.html

I find it ironic that both negative anti-goto & anti-semaphore viewpoints can
be held so strongly in modern heads when the person who originally pondered
thoughts about goto & semaphore came to different conclusions than heard in
recent years, such as those stated above.

Can anyone at University of Texas at Austin please pay Dr Dijkstra's office a
visit, knock on his door, and ask him to pay this thread on
comp.programming.threads a visit? I think that the person at the headwaters of
this multidecade river should be given the opportunity to respond to these
anti-goto & anti-semaphore statements, especially since his own goto-critiquing
statements were reportedly not necessarily seeking complete prohibition of goto
and since his seminal work on semaphore was definitely in the positive category
instead of the negative.

Alexander Terekhov

unread,
May 21, 2002, 7:32:38 PM5/21/02
to

Daniel Miller wrote:
[...]

> Can anyone at University of Texas at Austin please pay Dr Dijkstra's office a
> visit, knock on his door, and ask him to pay this thread on
> comp.programming.threads a visit?

I second that request! < no jokes >

In the meantime, lacking the clarifications w.r.t. BAD
aspects of POSIX (note: *not* POSIX Threads) semas,
I'll continue to believe strongly that the only 'right
approach' is:

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! SEMAS ARE BAD/REALLY BAD -- DON'T USE/AVOID THEM !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

regards,
alexander.

< my reply to another, but similar Daniel's article >

-------- Original Message --------
Message-ID: <3CEAD4C0...@web.de>
Date: Wed, 22 May 2002 01:14:08 +0200
From: Alexander Terekhov <tere...@web.de>
Newsgroups: comp.os.ms-windows.programmer.win32,comp.programming.threads,microsoft.public.win32.programmer.kernel
Subject: Re: The implementation of condition variables in pthreads-win32


Daniel Miller wrote:

[...RTOSes/realtime-semas-stuff...]

Daniel, could you please show us ANY solution
(in source {pseudo-}code, please) which would
demonstrate the "superiority" of semas? As for
my part, I've already mentioned a couple of
SPECIFIC reasons why to avoid them. Sorry, but
to me, you've just failed (so far ;-)) to
"address" ANY of them.

regards,
alexander.

P.S. <"selected" refs [a couple of "new ones, BTW] ;-)>

http://groups.google.com/groups?selm=c29b5e33.0201310709.3ffc3476%40posting.google.com
http://groups.google.com/groups?selm=slrn9e684t.hp.kaz%40cafe.net
http://groups.google.com/groups?selm=32F5D80A.446B%40zko.dec.com
http://groups.google.com/groups?selm=336DB34B.63DA%40zko.dec.com
http://groups.google.com/groups?selm=3573E4A3.99A61075%40zko.dec.com
http://groups.google.com/groups?selm=37400BDF.6E42E28%40zko.dec.com

Gerald Hilderink

unread,
May 22, 2002, 6:43:20 AM5/22/02
to

"Daniel Miller" <daniel...@tellabs.com> wrote in message
news:3CEAC2C4...@tellabs.com...

> Many engineers in realtime embedded systems have used semaphores
successfully
> for decades. Semaphores are an integral lucid portion of two very
successful
> and very widely deployed time-honored idioms:
(multi)producer-(multi)consumer
> and pool-dispenser. See
>
http://groups.google.com/groups?q=Daniel+Miller+group:comp.programming.threa
ds&hl=en&lr=&selm=3CD1864A.10401%40tellabs.com&rnum=3

Sure, after banging their heads hard against a wall several times. Monitors
are even worse.


> I find it ironic that anti-goto and anti-semaphore statements are
uttered in
> the same breath (so to speak) and by two different people no less. The 1)
> progenitor of the original goto-critique statements which have (somewhat
> inadvertently) precipitated a worldwide disdain for goto is the 2) very
same
> inventor of semaphores: Dr Edsger Wybe Dijkstra.

We need threads and semaphores to synchronize threads. But is multithreading
(i.e. threads, semaphores, monitors, etc.) THE paradigm to build our
software in? I think not. I think, that multithreading is best understood
(so to speak) by the processor, but not so good understood by us human mind.
Multithreading causes several discontinuities in the way we think about
systems.

Goto's can be compared with creating threads and not really with semaphores,
I guess.

In the early days of programming languages we had programming languages with
line numbers before statements and goto's with indexes. The idea of indexing
goto's was not a good idea, see Edward's article. Now we have programming
languages with goto's and labels, which are an improvement. Still,
ill-structured software can be EASILY made. The alternative is using clauses
(i.e. higher-level programming constructs), like while-wend, do-until,
for-next, switch. These clauses are simpler and ill-structured software is
LESS EASILY made.

Spawning threads is equal to goto's in a parallel form. Instead, an
excellent clause form (i.e. higher-level programming construct) would be the
parallel construct as defined in CSP (Communicating Sequential Processes by
Tony Hoare and Bill Roscoe).

Java uses semaphores in a clause form which is part of the language. This
seems to be elegant, but one has to be careful with these semaphores and
call-backs. I use CSP channels instead of monitors for synchronizing
processes and rarely use semaphores and shared objects. With CSP channels it
is easy to build concurrent software. Since, multithreading is not
object-oriented and CSP is, I use CSP for building our real-time control
systems and with great success. Also, with the CSP approach we do not suffer
from these semaphore and call-back hazards.

Gerald.


Mark Johnson

unread,
May 22, 2002, 9:14:45 AM5/22/02
to
Alexander Terekhov wrote:
>
> Vu Pham wrote:
> [...]
> > But besides the inappropriate logic in this problem, would you
> > please explain me why using many semaphores are not very good ?
>
> http://www.opengroup.org/onlinepubs/007904975/xrat/xsh_chap02.html#tag_03_02_08_03
> (please pay attention to "Much experience with semaphores shows...",
Hmm. I read that and come to a somewhat different conclusion that what
is stated in several subsequent messages. Semaphores (counting or not)
provide a specific synchronization mechanism. If your application DOES
fit that mechanism, you should use it. If not, then don't.

The system (a cluster of PC's, running a real time simulation, with a
non cache coherent shared memory interface) I am working on has two
levels of semaphores:
- one to control access within a single main program running on a two
CPU node of the cluster
- the second to control access to shared items across the whole cluster
The first level is implemented with spin locks using the CPU's native
instruction set - it is simple, efficient, and meets the need. The
second level is much "heavier" than the first since it operates over the
hardware interface between cluster nodes and must ensure correct cache
flushing (flush reads after getting the lock, flush writes before
releasing the lock).

You are going to have a hard time trying to convince me that posix
mutexes and condition variables provided with glibc will satisfy the
needs of our application. In the current series of code reviews we are
doing, we have found more problems with unsafe coding without the
semaphores (or cache flushes to ensure serialization) than we do with
them.
--Mark

Alexander Terekhov

unread,
May 22, 2002, 9:19:46 AM5/22/02
to

Gerald Hilderink wrote:

[...CSP_is_THE_paradigm_and_spawning_threads_is_equal_to_GOTO'S...]

G'Day Gerald,

Why don't you just drop a netnews-archive-link or two? ;-)

For example:

http://groups.google.com/groups?selm=thbI6.78137%24Uo2.2214104%40zwoll1.home.nl
(Subject: Re: Questions on "Realtime specification for Java")

Personally, I really like *these bits*:

"....
POSIX is not for everyone, but it is meant for the specialists among us.
....
POSIX is a good standard for low-level multithreading.
...."

BTW, I'd like to drop "my" link/view on this
"low-and-high" topic as well:

http://groups.google.com/groups?selm=3CBA8C49.B0F40E4A%40web.de
(Subject: Re: C++ and threads (invariant issues, actually))

"....
> C++ really does need language-level thread
> support, because there are so many language-level
> thread issues, of which this is only one. Yes,
> you can do everything with OS calls, but the
> language isn't giving you any help in getting it
> right. Are there any good designs for this being
> proposed?

FYI: ...."

And, BTW, perhaps you could be so kind and address
here (in this "CSP" thread) THIS one too (I failed
to find your reply on google ;-)):

http://groups.google.com/groups?selm=389EACE2.4F35E301%40bbnplanet.com
(Subject: Re: Multithreading underlies new development paradigm)

"From: Joe Seigh (jse...@bbnplanet.com)
Subject: Re: Multithreading underlies new development paradigm
Newsgroups: comp.arch, comp.programming.threads
Date: 2000/02/07

A point was raised earlier about the ability of CSP channels to handle concurrent
processing. Channels work by sending all of the data in toto. If you want to
have concurrent processing of data, you have to break the data into multiple
parts using multiple channels. As soon as you do that then the coordination
problem becomes equivalent in complexity to that of using normal threading
paradigms. Maybe some problems decompose into a solution nicely under your
paradigm but the exception doesn't prove the rule."

regards,
alexander.

Alexander Terekhov

unread,
May 22, 2002, 9:52:24 AM5/22/02
to

Gerald Hilderink wrote:
[...]

> Java uses semaphores in a clause form which is part of the language.

That's just a typo, I guess. *Mutexes* (silly/recursive ones,
unfortunately).

And, BTW (just in case you've missed it), Java is ALREADY
on the way, err. *gravitates BACK TO*, so to speak, *EARTH*
(i.e. PThreads -- "more flexibility at expense of verbosity",
"Similar to POSIX approach", "Most JVMs layer on POSIX condvars
anyway", "Is it possible to more closely align with RTSJ and/or
POSIX?", "...in accord with posix pthreads, it seems like a good
idea to..."), see the following links and slides:

http://www.jcp.org/jsr/detail/166.jsp
http://gee.cs.oswego.edu/dl/concurrency-interest/aims.html
http://gee.cs.oswego.edu/dl/concurrency-interest/jsr166-28jan02-4up.pdf

Well, frankly: I really wish you "the same"! ;-) ;-)

regards,
alexander.

Gerald Hilderink

unread,
May 22, 2002, 11:56:47 AM5/22/02
to

This is basically true for CSP I, like in occam. Sometimes breaking data
into multiple parts can be efficient with channels and sometimes inefficient
with channels. In CSP II, which is an extended version of CSP I, one can
send objects (like in OO) along channels according to send-by-copy or
send-by-reference. Thus, one can send a reference of a shared object along
channels. One can formally check if a process has exclusive ownership of the
shared object or one can formally check that multiple ownerships of the
shared object is protected by semaphores, like 'protected objects' in Ada.
However, the programming language needs to support some information for the
compiler to check for proper ownerships. Prof. Peter Welch (University of
Kent, UK) is developing a new version of occam that supports these features.
A Java prepocessor is also under development.

FYI, we also have call-channels which are very close to Ada's entry-accept
ideas. Thus, CSP is no longer resticted to producer-consumer models, but
also supports client-server models. Our CSP for Java library (called
Communicating Threads for Java) also has a 'real' PRIPAR and it supports
Alan Burns his idea of 'preference priorities'. Alan's idea has not yet been
implemented in Ada or in occam.

CSP processes can be as light-weight as threads. One should not compare CSP
processes with POSIX processes. However, CSP processes can be implement as
heavy as POSIX processes or as light as "active" objects. CSP processes can
be implemented in hardware as well.

With the CSP concepts we are able to impove the concurrency model of the UML
with true notion of events and processes. Processes and channels encapsulate
multithreading and these higher-level entities scale well with complexity.
The biggest advantages of using CSP in the UML is that we can eliminate
disconinuities between diagrams in the UML. Discontinuities between UML
diagrams is a serious problem in the UML. If one puts CSP and ROOM together
one can achief a briliant RT-UML version.

As you see, recently, much is going on in the field of 'CSP for software
engineering' and this stuff really goes above and beyond multithreading.

Gerald.
http://www.ce.utwente.nl/javapp


Alexander Terekhov

unread,
May 22, 2002, 12:33:54 PM5/22/02
to

Mark Johnson wrote:
[...]

>
> Alexander Terekhov wrote:
> >
> > Vu Pham wrote:
> > [...]
> > > But besides the inappropriate logic in this problem, would you
> > > please explain me why using many semaphores are not very good ?
> >
> > http://www.opengroup.org/onlinepubs/007904975/xrat/xsh_chap02.html#tag_03_02_08_03
> > (please pay attention to "Much experience with semaphores shows...",
> Hmm. I read that and come to a somewhat different conclusion that what
> is stated in several subsequent messages. Semaphores (counting or not)
> provide a specific synchronization mechanism. If your application DOES
> fit that mechanism, you should use it. If not, then don't.

That's OK. Please come up with an example (non-"toy" one,
if possible, please), which would "fit" w.r.t. A) and B)
and C) and D) and E) and F) from the "after-sleep" list
I've posted recently here:

http://groups.google.com/groups?threadm=3CEB6073.ACBCFD17%40web.de
(Subject: Re: inter-porcess events?)

> The system (a cluster of PC's, running a real time simulation, with a
> non cache coherent shared memory interface) I am working on has two
> levels of semaphores:
> - one to control access within a single main program running on a two
> CPU node of the cluster
> - the second to control access to shared items across the whole cluster

That's fine. Why not call them "simply" LOCKS? Do you need/use
it for LOCKING (to protect access to your shared data) or for
WAITING/SIGNALING (awaiting/notifying the occurrence of some
condition/state reflected in your shared "items"/data)?

> The first level is implemented with spin locks using the CPU's native
> instruction set - it is simple, efficient, and meets the need. The
> second level is much "heavier" than the first since it operates over the
> hardware interface between cluster nodes and must ensure correct cache
> flushing (flush reads after getting the lock, flush writes before
> releasing the lock).
>
> You are going to have a hard time trying to convince me that posix
> mutexes and condition variables provided with glibc will satisfy the
> needs of our application. In the current series of code reviews we are
> doing, we have found more problems with unsafe coding without the
> semaphores (or cache flushes to ensure serialization) than we do with
> them.

I'm NOT sure what are you driving at... memory sync./visibility?

It (mem.sync), being essential part of any *locking*
protocol, IS provided perfectly by *MUTEX*[1] (and by
other LOCKS too -- spinlocks and rwlocks).

Well, semas ALSO provide it, but I see no reason why
their mem.sync should be any/somehow better than the
one provided by TRUE locks (mutexes, in the first
place).

In any event, it (injecting ordering constraints) does
NOT really have anything to do with "cache flushes",
according to:

http://groups.google.com/groups?selm=c29b5e33.0202150632.6d579f24%40posting.google.com
(Subject: Re: Can multiple threads set a global variable simultaneously?)

"for example". ;-)

regards,
alexander.

[1] Well, the standard also requires that condvar signaling
functions should provide "memory.sync"[2]. I disagree,
whatever it means (the standard DOES NOT specify any
"formal" protocols for "memory.sync", BTW), it should
NOT be required w.r.t. CV's signal/broadcast. My "proof"
can be found here:

http://groups.google.com/groups?threadm=c29b5e33.0202010305.5c12381d%40posting.google.com
(Subject: Re: thread Safe singleton)

also:

http://groups.google.com/groups?threadm=3C615A7E.C61764C7%40web.de

"....
Well, I was thinking (rather *uneducated* guess) of
something along the lines of IA32's "MTRRs"[1] -- so
that some of the condition's internal structure/data
(e.g. queue) could be allocated in a more restricted/
*in-order* memory, which (while providing *internal*
data coherency/visibility) would have no effect
whatsoever on the rest of application (regular)
data/memory-visibility...

Or am I way off the mark with such ideas?
...."

So, basically, I think that the following statement
from the recent Austin Group Meeting minutes:

"XBD ERN 11: (Ulrich) Adding this requirement would
make the function more costly for no actually gain."

IS, *actually* MORE APPLICABLE to *XBD ERN 10*
(and XSH ERN 44 TOO, BTW); *not* XBD ERN 11:

http://www.opengroup.org/austin/aardvark/finaltext/xbdbug.txt
(see "Enhancement Request Number >??<" for XBD ERNs)

http://www.opengroup.org/austin/aardvark/finaltext/xshbug.txt
(see "Enhancement Request Number >??<" for XSH ERNs)

http://www.opengroup.org/austin/docs/austin_106.html
("Minutes of May 2002 Meeting")

[2] http://groups.google.com/groups?selm=3CBFD38B.7115B864%40web.de
(Subject: Re: Fastest thread communication with pthreads?)

Mark Johnson

unread,
May 22, 2002, 1:50:41 PM5/22/02
to
Alexander Terekhov wrote:
>
> Mark Johnson wrote:
> [...]
> > [removed stuff apparently not part of my comment]

> > The system (a cluster of PC's, running a real time simulation, with a
> > non cache coherent shared memory interface) I am working on has two
> > levels of semaphores:
> > - one to control access within a single main program running on a two
> > CPU node of the cluster
> > - the second to control access to shared items across the whole cluster
>
> That's fine. Why not call them "simply" LOCKS? Do you need/use
> it for LOCKING (to protect access to your shared data) or for
> WAITING/SIGNALING (awaiting/notifying the occurrence of some
> condition/state reflected in your shared "items"/data)?
>
I guess we (and others) are dancing around terminology here. To me,
locks and semaphores have the same semantic effects. To quote from
Dijkstra's paper (The Structure of the "THE" Multiprogramming System,
1968)...
A process, "Q" say, that performs the operation "P(sem)" decreases the
value of the semaphore called "sem" by 1. If the resulting value of the
semaphore concerned is nonnegative, process Q can continue with the
execution of its next statement; if however, the resulting value is
negative, process Q is stopped and booked on a waiting list associated
with the semaphore concerned.... [the V(sem) operation is defined in
similar terms]

I don't care if you call this a semaphore or a lock, the effect to the
user program is the same. A process trying to access a semaphore can be
blocked by some means (can be a queue, can be a spin lock, or whatever)
until another process has released the semaphore. It is a nice, simple
model with well defined characteristics.

> > You are going to have a hard time trying to convince me that posix
> > mutexes and condition variables provided with glibc will satisfy the
> > needs of our application. In the current series of code reviews we are
> > doing, we have found more problems with unsafe coding without the
> > semaphores (or cache flushes to ensure serialization) than we do with
> > them.
>
> I'm NOT sure what are you driving at... memory sync./visibility?
>

If you refer to "sync" as sequential ordering of memory operations -
then yes.

> It (mem.sync), being essential part of any *locking*
> protocol, IS provided perfectly by *MUTEX*[1] (and by
> other LOCKS too -- spinlocks and rwlocks).
>

To the extent that it understand the hardware on which it is running. I
agree that the Posix locking mechanisms will handle the single node in
the cluster, but it will not handle the cluster wide locks that we need
(since it doesn't distinguish between memory address in the local
machine from those on other machines across the non cache coherent
shared memory interface). That was my point - glibc doesn't know about
my hardware so it can't do a sufficient job without modification.

> In any event, it (injecting ordering constraints) does
> NOT really have anything to do with "cache flushes",
> according to:
>
> http://groups.google.com/groups?selm=c29b5e33.0202150632.6d579f24%40posting.google.com
> (Subject: Re: Can multiple threads set a global variable simultaneously?)
>

I am well aware of the problems with a weak memory model. We have a
strong memory model in a node of the cluster and a weak memory model
across the cluster. The problem is fixing code built to one standard to
work in the other.
--Mark

Alexander Terekhov

unread,
May 23, 2002, 2:20:54 PM5/23/02
to

Mark Johnson wrote:
[...]

> > That's fine. Why not call them "simply" LOCKS? Do you need/use
> > it for LOCKING (to protect access to your shared data) or for
> > WAITING/SIGNALING (awaiting/notifying the occurrence of some
> > condition/state reflected in your shared "items"/data)?
> >
> I guess we (and others) are dancing around terminology here. To me,
> locks and semaphores have the same semantic effects. To quote from
> Dijkstra's paper (The Structure of the "THE" Multiprogramming System,
> 1968)...

[snip P/V stuff]

Mark, *I am...* yeah: DANCING, heck, all along, around THIS:

"Semaphore Lock Operation

An operation that is applied to a semaphore. If, prior to the
operation, the value of the semaphore is zero, the semaphore
lock operation shall cause the calling thread to be blocked
and added to the set of threads awaiting the semaphore;
otherwise, the value shall be decremented.

Semaphore Unlock Operation

An operation that is applied to a semaphore. If, prior to the
operation, there are any threads in the set of threads awaiting
the semaphore, then some thread from that set shall be removed
from the set and becomes unblocked; otherwise, the semaphore
value shall be incremented."

around THIS ("Realtime"[1] stuff; semget()-semaphores associated
with the X/Open System Interface Extension (XSI) aside, "for a
moment"):

http://www.opengroup.org/onlinepubs/007904975/functions/sem_wait.html
http://www.opengroup.org/onlinepubs/007904975/functions/sem_post.html

and, around THIS:

http://www.opengroup.org/onlinepubs/007904975/xrat/xsh_chap02.html#tag_03_02_09

"....
A semaphore is defined as an object that has an integral value
and a set of blocked processes associated with it. If the value
is positive or zero, then the set of blocked processes is empty;
otherwise, the size of the set is equal to the absolute value
of the semaphore value. The value of the semaphore can be
incremented or decremented by any process with access to the
semaphore and must be done as an indivisible operation. When
a semaphore value is less than or equal to zero, any process
that attempts to lock it again will block or be informed that
it is not possible to perform the operation.

A semaphore may be used to guard access to any resource
accessible by more than one schedulable task in the system.
It is a global entity and not associated with any particular
process. As such, a method of obtaining access to the semaphore
has to be provided by the operating system. A process that wants
access to a critical resource (section) has to wait on the
semaphore that guards that resource. When the semaphore is
locked on behalf of a process, it knows that it can utilize
the resource without interference by any other cooperating
process in the system. When the process finishes its operation
on the resource, leaving it in a well-defined state, it posts
the semaphore, indicating that some other process may now
obtain the resource associated with that semaphore.

In this section, mutexes and condition variables are specified
as the synchronization mechanisms between threads.

These primitives are typically used for synchronizing threads
that share memory in a single process. However, this section
provides an option allowing the use of these synchronization
interfaces and objects between processes that share memory,
regardless of the method for sharing memory.

Much experience with semaphores shows that there are two
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
distinct uses of synchronization: locking, which is typically
of short duration; and waiting, which is typically of long or
unbounded duration. These distinct usages map directly onto
mutexes and condition variables, respectively.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Semaphores are provided in IEEE Std 1003.1-2001 primarily to
provide a means of synchronization for processes; these processes
may or may not share memory. Mutexes and condition variables are
specified as synchronization mechanisms between threads; these
threads always share (some) memory. Both are synchronization
paradigms that have been in widespread use for a number of years.
Each set of primitives is particularly well matched to certain
problems.

With respect to binary semaphores, experience has shown that
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
condition variables and mutexes are easier to use for many
synchronization problems than binary semaphores. The primary
reason for this is the explicit appearance of a Boolean
predicate that specifies when the condition wait is satisfied.
This Boolean predicate terminates a loop, including the call
to pthread_cond_wait(). As a result, extra wakeups are benign
since the predicate governs whether the thread will actually
proceed past the condition wait. With stateful primitives,
such as binary semaphores, the wakeup in itself typically
means that the wait is satisfied. The burden of ensuring
correctness for such waits is thus placed on all signalers
of the semaphore rather than on an explicitly coded Boolean
predicate located at the condition wait. Experience has
shown that the latter creates a major improvement in safety
and ease-of-use.

Counting semaphores are well matched to dealing with
producer/consumer problems, including those that might exist
between threads of different processes, or between a signal
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
handler and a thread. In the former case, there may be little
or no memory shared by the processes; in the latter case,
one is not communicating between co-equal threads, but
between a thread and an interrupt-like entity. It is for
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


these reasons that IEEE Std 1003.1-2001 allows semaphores

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


to be used by threads.

^^^^^^^^^^^^^^^^^^^^^

Mutexes and condition variables have been effectively used
with and without priority inheritance, priority ceiling,
and other attributes to synchronize threads that share
memory. The efficiency of their implementation is comparable
to or better than that of other synchronization primitives
that are sometimes harder to use (for example, binary semaphores).
Furthermore, there is at least one known implementation of Ada
tasking that uses these primitives. Mutexes and condition
^^^^^^^^^^^^^^^^^^^^^


variables together constitute an appropriate, sufficient,

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


and complete set of inter-thread synchronization primitives.

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"

[...POSIX/clustering/cluster wide stuff...]

Uhmm.

Have you "evaluated" technologies/"ideas" related to IBM Parallel
Sysplex clustering... COUPLING FACILITY [2] (with its Lock, Cache,
and Queue/List "behavioral models" -- "structures"), I mean? ;-)

regards,
alexander.

[1] http://www.opengroup.org/onlinepubs/007904975/functions/xsh_chap02_08.html#tag_02_08

[2] http://researchweb.watson.ibm.com/journal/sj/362/nick.html

Daniel Miller

unread,
May 23, 2002, 5:52:04 PM5/23/02
to
Mark Johnson wrote:

> Alexander Terekhov wrote:
>
>>Mark Johnson wrote:

[...snip...]


> I guess we (and others) are dancing around terminology here. To me,
> locks and semaphores have the same semantic effects.

[...snip...]

> I don't care if you call this a semaphore or a lock, the effect to the
> user program is the same.

[...snip...]


>>>You are going to have a hard time trying to convince me that posix
>>>mutexes and condition variables provided with glibc will satisfy the
>>>needs of our application. In the current series of code reviews we are
>>>doing, we have found more problems with unsafe coding without the
>>>semaphores (or cache flushes to ensure serialization) than we do with
>>>them.

[...snip...]


(I am really going to try to word the <impartial></impartial> block of text
in purely objective fashion in an attempt to play the role of an external
3rd-party observer for a moment as an attempt at starting to form some sort of
convergent common ground and/or tolerance.)

<impartial>=============================================================

I think that another related thing which we are dancing around in all of the
semaphore versus mutex&condition-variable postings is the following:

There are two perspectives regarding multithread programming:
1) bottom up
2) top down.

The bottom up perspective tends to focus on identifying a recommended minimum
set of thread-synchronization primitives which are necessary and sufficient for
all points of usage. Once such a necessary & sufficient minimum set of
thread-synchronization primitives has been established, then push the frontier
of thought upward to application-domain to educate how the minimum set of
thread-synchronization primitives can be successfully applied.

The top down perspective tends to focus on the application of
established-practice idioms which are useful at expressing the breadth & variety
of MT software and/or realtime embedded software in a concise & convenient form.
Once the desired-state of a set of idioms in the application-domain has been
established, then push the frontier of thought downward, shopping for
implementation mechanisms which accomplish these idioms correctly & most
efficiently.

</impartial>=============================================================

In my opinion, Alexander and certain other people appear to be subscribers of
the bottom-up school of thought. They have a pre-established list of
thread-synchronization primitives which the bulk of
multithread(-intraaddressspace) software should be written (except for
semaphores between address-spaces and except for posting to semaphores from an
asynchronous signal/interrupt handler).

Obviously, I and certain other people are subscribers of the top-down school
of thought. I have a pre-established list of idioms which I expect (i.e.,
demand!) to have at my disposal when writing MT software. These idioms are the
following:

1) synchronization for exclusive use of common resource:
interthread-*intra*addressspace-intra*uni*processor exclusively locking a
resource for short time duration

2) synchronization for exclusive use of common resource:
interthread-*inter*addressspace-intra*uni*processor exclusively locking a
resource for short time duration

3) synchronization for exclusive use of common resource:
interthread-*intra*addressspace-intra*multi*processor exclusively locking a
resource for short time duration

4) synchronization for exclusive use of common resource:
interthread-*inter*addressspace-intra*multi*processor exclusively locking a
resource for short time duration

5) synchronization for exclusive use of common resource:
interthread-*inter*addressspace-*inter*processor exclusively locking a resource
for short time duration

6) synchronization for shared use of common resource:
interthread-*intra*addressspace-*intra*processor shared read-only locking a
resource for short time duration

7) synchronization for shared use of common resource:
interthread-*inter*addressspace-*intra*processor shared read-only locking a
resource for short time duration

8) synchronization for shared use of common resource:
interthread-*inter*addressspace-*inter*processor shared read-only locking a
resource for short time duration

9) asynchronization for hand-off of units-of-work:
multiple producer threads pushing a data-structure into a FIFO queue which can
be pended on by multiple consumer threads in the *same* address-space on the
same processor (single producer and/or single consumer supported as well as
degenerate case. When multiple consumers pend on the same such FIFO queue, they
form an implicit thread pool of consumers whose awakening may be scheduled by
the operating system in kernel-space without assistance from user-space.)

10) asynchronization for hand-off of units-of-work:
multiple producer threads pushing a data-structure into a FIFO queue which can
be pended on by multiple consumer threads in *different* address-spaces on the
same processor (single producer and/or single consumer supported as well as
degenerate case. When multiple consumers pend on the same such FIFO queue, they
form an implicit thread pool of consumers whose awakening may be scheduled by
the operating system in kernel-space without assistance from user-space.)

11) asynchronization for hand-off of units-of-work:
multiple producer threads pushing a data-structure into a FIFO queue which can
be pended on by multiple consumer threads in different address-spaces on a
*different* processor (single producer and/or single consumer supported as well
as degenerate case. When multiple consumers pend on the same such FIFO queue,
they form an implicit thread pool of consumers whose awakening may be scheduled
by the operating system in kernel-space without assistance from user-space.)

12) dispensing a resource from a common pool:
interthread-*intra*addressspace-*intra*processor dispensing permission to have
exclusive access to a resource in a common pool

13) dispensing a resource from a common pool:
interthread-*inter*addressspace-*intra*processor dispensing permission to have
exclusive access to a resource in a common pool

14) dispensing a resource from a common pool:
interthread-interaddressspace-*inter*processor dispensing permission to have
exclusive access to a resource in a common pool

15) synchronization of arrival:
interthread-*intra*addressspace-*intra*processor arrival of the required number
of threads

16) synchronization of arrival:
interthread-*inter*addressspace-*intra*processor arrival of the required number
of threads

17) synchronization of arrival:
interthread-interaddressspace-*inter*processor arrival of the required number of
threads

18) custom:
interthread-*intra*addressspace-intraprocessor
thread-synchronization/waiting mechanisms which do not fall into the
above-listed noncustom categories or if the preferred implementation (in neither
POSIX form nor nonPOSIX) is absent for any of the above-listed noncustom categories

19) custom:
interthread-*inter*addressspace-intraprocessor
thread-synchronization/waiting mechanisms which do not fall into the
above-listed noncustom categories or if the preferred implementation (in neither
POSIX form nor nonPOSIX) is absent for any of the above-listed noncustom categories


Of each of these idioms I consider the following implementations as preferred.

1) POSIX mutex iff 6 is absent in design;
POSIX rwlock iff 6 is present in design

2) POSIX mutex iff 7 is absent in design;
POSIX rwlock iff 7 is present in design

3) POSIX spinlock iff 6 is absent in design;
POSIX mutex or POSIX semaphore iff POSIX spinlock absent from OS and 6 is absent
from design;
POSIX rwlock iff 6 is present in design

4) POSIX spinlock iff 7 is absent in design;
POSIX mutex or POSIX semaphore iff POSIX spinlock absent from OS and 6 is absent
from design;
POSIX rwlock iff 7 is present in design

5) datalink-layer or network-layer protocols

6) POSIX rwlock

7) POSIX rwlock

8) datalink-layer or network-layer protocols

9) POSIX semaphore encapsulated within a producer-consumer class:
to eliminate leaks, only push signals/increments semaphore
to eliminate leaks, only pop waits/decrements semaphore

10) POSIX semaphore encapsulated within a producer-consumer class
to eliminate leaks, only push signals/increments semaphore
to eliminate leaks, only pop waits/decrements semaphore

11) POSIX datalink-layer or network-layer protocols coupled with a semaphore
encapsulated within a producer-consumer class on the destination processor
to eliminate leaks, only push signals/increments semaphore
to eliminate leaks, only pop waits/decrements semaphore

12) POSIX semaphore encapsulated within a pool-dispenser class:
to eliminate leaks, only guard ctor signals/increments semaphore
to eliminate leaks, only guard ctor waits/decrements semaphore

13) POSIX semaphore encapsulated within a pool-dispenser class:
to eliminate leaks, only guard ctor signals/increments semaphore
to eliminate leaks, only guard ctor waits/decrements semaphore

14) datalink-layer or network-layer protocols to a single semaphore (located
on a single processor) encapsulated within a pool-dispenser class:
to eliminate leaks, only guard ctor signals/increments semaphore
to eliminate leaks, only guard ctor waits/decrements semaphore

15) POSIX barrier

16) POSIX barrier

17) datalink-layer or network-layer protocols

18) POSIX condition variables

19) POSIX condition variables


You see, when I go shopping in top-down fashion for the best implementation
for my MT idioms, I do not care in the slightest what the necessary & sufficient
minimum subset of thread-synchronization primitives are. I care first &
foremost about best-of-breed implementation for that idiom and then secondarily
about a custom condition-variable-based implementation if and only if my
preferred best-of-breed implementation is absent for that particular OS.

Also note that by providing a ternary set of
interthread-intraaddressspace-intraprocessor,
interthread-interaddresspace-intraprocessor, and
interthread-interaddressspace-interprocessor variants, one can move code
dynamically around in an embedded real-time system composed of multiple
processors, given that each of these variants has a compile-time-compatible
class interface. I can choose to collocate MT code within the same
address-space, disperse MT code among separate address-spaces
themselves collocated within the same processor, or distribute MT code among
separate processors as I see fit and as performance concerns dictate. This is
another essential kind of portability which most narrower definitions of
portability ignore.

This set of MT idioms is my vision coupled with a pthreads++/POSIX.C++ API
for what should be commonplace and standardized for MT C++ software. Because
Boost.threads currently accomplishes only #1 and #18, I consider Boost.threads
about 2/19 = approximately 10.5% along the way toward meeting my expectations.
(The % of my expectations which Boost.threads meets drops drastically further
when I consider support for scheduling policies and other tunabilities which
might or might not be supported on a per-OS basis.) In my school of thought 60%
is a D, 70% is C, 80% is a B, and 90% is an A. <= 10.5% is far less than the
minimum 60% required for a passing grade in my school of thought. The % of my
expectations met by RogueWave Threads.h++ is much much higher than 10.5% due to
their API for a far greater number of MT idioms & tunabilities.

Alexander, if you are implementing the idioms for such an API on a particular
platform, please feel free to implement all of the intraaddress-space ones via
condition-variables&mutexes alone---although that would be an unfortunate
limitation of producer-consumer, prohibiting it from pushing messages into a
FIFO queue from a asynchronous signal/interrupt handler.

When I implement them myself however, I just might encapsulate a semaphore
within (multi)producer-(multi)consumer and within pool-dispenser. I would
prefer that antisemaphore bias not obstruct me in any way from easily applying
semaphore in such an appropriately encapsulated controlled environment.
Ultimately, it comes down to implementing each of these idioms in multiple ways
and testing on a per-platform basis which ones perform best.

Mark Johnson

unread,
May 23, 2002, 5:47:05 PM5/23/02
to
Alexander Terekhov wrote:
> [snip 150 line reply to a far shorter comment]
You may want to calm down. You are not going to convince me (and
others?) with this kind of response. I honestly don't care if the Open
Group considers mutexes and condition variables ARE an appropriate,
sufficient, and complete solution. Making that kind of argument brings
to mind the original tasking definitions in Ada. The Ada rationale made
similar glowing statements about the solution chosen. However, it was
almost impossible with that method of tasking to do something as simple
as scheduling a 10hz task. Complete, appropriate, and sufficient doesn't
cut it if a simple method works well. [perhaps I should point you to
Richard Gabriel's article titled "Lisp: Good News, Bad News, How to Win
Big" for similar arguments and I won't paste them into my reply...]

By the way, if you didn't notice, the OP said that semaphores were not
what he needed and changed his design. Good, he got to a better solution
to his real world problems. As far as he is concerned, we could take
this whole discussion off line and turn down the noise on the newsgroup.

> [...POSIX/clustering/cluster wide stuff...]
>
> Uhmm.
>
> Have you "evaluated" technologies/"ideas" related to IBM Parallel
> Sysplex clustering... COUPLING FACILITY [2] (with its Lock, Cache,
> and Queue/List "behavioral models" -- "structures"), I mean? ;-)
>

That would be nice, but there are a few drawbacks to that...
- when can I get such a complete system for less than $80k
- can it interface to four VME racks with >20 Mbyte/sec transfer rates
- if I can't pass a pointer between nodes of the cluster to get access
to data, our application has to change
The original system (and currently in use) is a 4GB, 28 CPU SGI
Challenge XL. Maintenance on a system like that is about $60k/year. The
cluster of PC's we are replacing it with runs about $20k for the systems
and $60k for the interconnects. An Origin from sgi would run a few
hundred thousand. I can't expect IBM to be in the right price range
either.

Part of the reason we are moving off of SGI is the design change to
cc:NUMA in the Origin series. Latency between nodes is several times
higher than within a node. This impacts our system design enough to
rewrite the messaging layer of our code. If I have to do that, I can
help pay for the rewrite by moving to cheaper hardware (not the best
hardware - stuff that works & is cheap).

For our specific application, we would have been better off using a
layer such as MPI. There is direct support for that with the hardware we
have selected (as well as several others). However, it is a little too
late to make such a change with well over a million lines of code :-(.

Don't get me wrong, I would love to deliver a system using a Sysplex or
Origin machine, much the same way I wish I could have delivered Vaxen 20
years ago. But at the price / performance points they are at, I don't
expect to be able to anytime soon. Gabriel coined the term "Worse is
Better" - I have seen it in action and it works.
--Mark

Alexander Terekhov

unread,
May 24, 2002, 5:30:54 AM5/24/02
to

Mark Johnson wrote:
[...]

>
> Alexander Terekhov wrote:
> > [snip 150 line reply to a far shorter comment]

What's your point (w.r.t. the size [*mostly quotes*,
BTW] of my reply), I mean?

> You may want to calm down.

Gee! I always (well, since a couple of wars [won]
in my village's Kindergarten [a couple of years
ago]) stay 'cool'! ;-) ;-)

> You are not going to convince me (and others?)

Whom ("others?") do you mean? Names, tel.numbers,
please. ;-)

[...]


> [perhaps I should point you to Richard Gabriel's article
> titled "Lisp: Good News, Bad News, How to Win Big" for
> similar arguments and I won't paste them into my reply...]

Do you have a link? Please.

regards,
alexander.

Gerald Hilderink

unread,
May 24, 2002, 6:19:47 AM5/24/02
to
"Daniel Miller" wrote :


Your top-down approach gives people a very good reason not to use
multithreading, since it makes life too complex, i.e. complex in reasoning,
complex in implementing, no formal foundation, and it goes beyond the
primary focus. I think that the primary focus should be on the application
(analysis/requirements/design) and I am afraid that these idioms and
implementation make its architecture muddy. I belief that concurrency
should go along with the requirements and should not be dominant in
concurrent software design. Concurrency should make developing software
simpler and not harder. MT is an important source for complexity and not
simplicity. Something goes wrong!

Look around us...describing our real world in the top-down approach is hard,
if not impossible. The bottom-up approach provides abstract notion about
processes, events, and communication, in which we think about systems in a
natural way. Then a small set of fundamental synchronization primitives can
be used to realize this. Both approaches may very well end up with the
similar solutions but at different costs (e.g. reliability, robustness,
speed, proof, .). I am sure that the bottom-up approach can deal with many
of your idioms. Furthermore, the results of the top-down approach are not
very WYSIWYG to me and easily results in discontinuities between design and
implementation.

I advocate the bottom-up approach for my entire design and sometimes a
top-down approach for lower-level implementation issues. The breadth &
variety of MT is something I do not need when I design a program. MT in
design is hazardous and inherently complex. There are better ways to start
with.

Alexander Terekhov

unread,
May 24, 2002, 7:11:47 AM5/24/02
to

Daniel Miller wrote:

[...good stuff...]

Daniel, I really need more than 3..10 minutes (or so) it takes
to {re}build my C++ jobs on damn slow/busy hosts we have here
(time windows I use for netnews) to comprehend your stuff and
try to reply to the rest of your points. (I'll probably throw
it into my WorkPad organizer and/or ThinkPad and try to find
some time for it over the weekend). For now, I have just one
comment/question:

> Alexander, if you are implementing the idioms for such an API on a particular
> platform, please feel free to implement all of the intraaddress-space ones via
> condition-variables&mutexes alone---although that would be an unfortunate
> limitation of producer-consumer, prohibiting it from pushing messages into a
> FIFO queue from a asynchronous signal/interrupt handler.

Why not use *SIGEV_THREAD*, dedicated thread(s)/sigwait(),
and/or, perhaps, sort-of try to get rid of "async.signals"
(interrupts) altogether?!?! (async-"cancel"-safe regions
[for async.exception] SHOULD STAY INTACT, however!!! ;-))

regards,
alexander.

Mark Johnson

unread,
May 24, 2002, 10:26:50 AM5/24/02
to
Gerald Hilderink wrote:
>
> "Daniel Miller" wrote :
>
> > There are two perspectives regarding multithread programming:
> > 1) bottom up
> > 2) top down.
> > [very nice explanation snipped]

> Your top-down approach gives people a very good reason not to use
> multithreading, since it makes life too complex, i.e. complex in reasoning,
> complex in implementing, no formal foundation, and it goes beyond the
> primary focus.
As a "top down" kind of guy, I must disagree. Perhaps it is a side
effect of how I was trained (in school and at my company), but one of
the first things I start off with is a context diagram. What is "inside
the system", what is "outside the system", and the interface between
them. That is key information required to bound the scope of the system
being implemented. You can then do a top-down decomposition / bottom-up
implementation of the system. There are several books on the shelf
behind me that describe this for "structured analysis" or "object
oriented" approaches.

> I think that the primary focus should be on the application
> (analysis/requirements/design) and I am afraid that these idioms and
> implementation make its architecture muddy.

I suggest taking a look at what Hatley/Pirbhai proposed in 1987 (or in
1985 Ward/Mellor) where you describe what the system must do in parallel
with how it is being performed. You do the cross checks at each level of
detail and confirm that the system will work when you finally assemble
it.

> I belief that concurrency
> should go along with the requirements and should not be dominant in
> concurrent software design. Concurrency should make developing software
> simpler and not harder. MT is an important source for complexity and not
> simplicity. Something goes wrong!
>

I am not quite sure of your point here. Concurrency can simplify the
implementation while increasing the variability of the system. If I go
back to an extremely old system design approach, run everything in order
at a fixed rate - the system is harder to construct but has high
repeatability [it always does the same steps in the same order]. You
might have to break a long computation into several smaller steps to fit
within the constraints of that system. When I change to multiple threads
of execution, the system can be easier to produce, but harder to use
since it does not have the same repeatable operation [due to external
stimulus, A occurs before B this time and B before A the next time].
That is the nature of the systems we produce.

> Look around us...describing our real world in the top-down approach is hard,
> if not impossible.

I disagree.

> The bottom-up approach provides abstract notion about
> processes, events, and communication, in which we think about systems in a
> natural way. Then a small set of fundamental synchronization primitives can
> be used to realize this.

Natural to you, but not to me. Don't get me wrong, I have seen (and
implemented several systems) cases where the assembly and interaction of
small "objects" (for lack of a better word) produces a robust solution
for a problem. To provide an example of that, let me describe a system I
am aware of.

The staff at Wright Patterson Air Force Base put together an
aerodynamics model based on ideas from finite element modeling. This
piece of the wing would push a chunk of air down, providing an up vector
of force on the adjoining elements of the wing. The wing was assembled
from many of these elements, as well as elements for the air and ground
around the wing. The model accurately reflected the conditions of normal
flight, stall (inadequate lift), ground effects (extra lift when near
the ground), and could be used for wings, propellors, and helicopter
rotors.

> Both approaches may very well end up with the
> similar solutions but at different costs (e.g. reliability, robustness,
> speed, proof, .).

The example I describe is not as efficient as those delivered
previously. Execution speed is still a constraint in many systems which
would preclude this approach from being used.

> I am sure that the bottom-up approach can deal with many
> of your idioms. Furthermore, the results of the top-down approach are not
> very WYSIWYG to me and easily results in discontinuities between design and
> implementation.
>

As I mentioned above - it does not have to be.

> I advocate the bottom-up approach for my entire design and sometimes a
> top-down approach for lower-level implementation issues. The breadth &
> variety of MT is something I do not need when I design a program. MT in
> design is hazardous and inherently complex. There are better ways to start
> with.

Again, many people are trained the other way and have built plenty of
systems in a top down manner with success. As you note - top down does
work in certain situations. Also, MT designs can be very simple but
exhibit complex behavior (the aerodynamic example above). It depends on
what you choose to implement and how you do it. You should use the right
tool for the right job (and not just a hammer on every nail and screw...
:-)).
--Mark

Daniel Miller

unread,
May 24, 2002, 4:02:37 PM5/24/02
to
Gerald Hilderink wrote:


Your line of reasoning appears to conflict internally with itself.

On one hand you seem to be arguing against idioms and patterns altogether.
Rather you seem to be arguing for a bottom-up approach as defined by me along
this thread, not as defined in any prior art. Do you realize which
ramifications your line of reasoning leads to? By arguing for the bottom-up
approach, you would start with the thread-synchronization primitives as a
mandate, then contort an architecture to best fit the restricted solution-space
which was determined a priori. This bottom-up perspective of
thread-primitives-contaminate-architectural-decisions appears to directly &
thoroughly conflict with your "primary focus ... on the application
(analysis/requirements/design)". Based on what you have written in your
posting, I think that you are top-down, but just don't realize it yet.

On the other hand, despite your words to the contrary, you seem to driving
hard toward top-down approaches, where "top-down" is as defined by me along this
branch of this thread, not as defined in any prior art. You seem to be saying
that one should start with analyzing the application-space, form an intended
architecture which applies to that application-space, shop for idioms/patterns
which serve that intended architecture, (if the shopping does not turn up any
existing idioms/patterns, then invent a new idiom/pattern to meet the
architecture's needs), then go shopping for possible implementations of those
idioms, and then and only then worry about MT intricacies.


> Look around us...describing our real world in the top-down approach is hard,
> if not impossible.


But ironically, elsewhere in your line of reasoning you argue hard for a
top-down approach to start with application-space/problem-space and then later
to worry about thread-synchronization primitives or idioms or patterns which
elegantly support the higher-layer decisions. The alternative which you argue
hard against is to start with the a restricted set of necessary & sufficient
thread-synchronization primitives and then to progressively push upward toward
the application-space.

See below for real-world demonstration of my top-down approach of going
shopping at a school-of-thought store of already-made previously-established
idioms/patterns.

> The bottom-up approach provides abstract notion about
> processes, events, and communication, in which we think about systems in a
> natural way.


I cannot speak for what is natural for you, but to start with a restricted
minimal set of thread-synchronization primitives is abhorrently unnatural for
me. (Ultimately the minimal set of thread-synchronization primitives on
uniprocessors is: the test-and-set instruction or noninterrupted equivalent
atomic sequence of instructions; that is where the most-pure bottom-up person
would start.)

When analyzing the application-space/problem-space, I don't give a hoot about
which thread-synchronization primitive someone is going to restrict me to have.
Likewise when authoring an architecture, I don't give a hoot about which
thread-synchronization primitives someone is going to restrict me to have.
Instead as an architect I want to start talking about which established-practice
idioms will and will not comprise the intended architecture, deciding between
the alternatives based directly on whether they fit the
application-space/problem-space or not:

For example:
This (hardware) architecture will permit multiple processors (i.e., the Von
Neumann sequential-execution control-flow processor idiom/pattern instead of,
say, a massively parallel data-flow optical-computer idiom/pattern).
This architecture will permit multiple address-spaces per processor (i.e.,
the UNIX, VMS process idiom/pattern as opposed to the pSOS idiom/pattern of only
one address-space per processor).
This architecture will permit multiple threads per address-space (i.e., the
macroscopic multithread idiom/pattern under discussion in this newsgroup as
opposed to the antithesis at http://user.cs.tu-berlin.de/~kunegis/hack/threads/
which actually was a viewpoint held by an unfortunate minority at one of my
previous employers).
This architecture will be as asynchronous nonblocking as possible (i.e., the
[multi-]producer-[multi]consumer RTOS-style asynchronous message-queue as
opposed to a 100% thread-synchronization-based approach).
And so forth drilling down further and further to refine an
ever-more-detailed architecture which matches the problem-space. Obviously this
top-down drill-down technique is iterative, based on ever-progressing learning
or based on ever-increasing revelation of the problem-space's intracies or based
on rapid-development prototypes.
After or during the refinement of the architectural principles, some sort of
decomposition of the system into smaller units occurs. Again that is iterative.
After decomposition (e.g., breaking into topical subsystems), then high-level
design of those subsystems follows, followed by low-level design.

It is not until high-level and low-level design phases that I would worry
about which restricted set of thread-synchronization primitives are dictated on
a particular platform. The high-level design would simply check: "Does some
sort of sufficient set of thread-synchronization primitives exist on the
intended platform? I don't care which ones they are at high-level design-time,
just do I have one or more adequate sets?" At low-level design, I would care
enough to really go shopping for the best/most-efficient/correctly-working
thread-synchronization primitive for each idiom/pattern my architecture &
high-level design found natural.

As one can see, this drill-down of further & further refinement (which I call
top-down on this thread) is very natural for at least this human being (i.e.,
me) and probably thousands upon thousands of others if the popularity of
software engineering, OO, patterns, and idioms in our industry is any guide. In
fact it appears to be quite natural to you too based on your desire to start at
the analysis-time application-layer/problem-space to progress downward instead
of the coding-time thread-synchronization primitive layer/solution-space to
impose a technocratic solution in boilerplate fashion on the problem-space.

> Then a small set of fundamental synchronization primitives can
> be used to realize this.


Ahh! You think that I use all 19 in every unit of software that I write. No
no no, these 19 form my minimal set of weapons that I expect to have in my
arsenal in case I need them. I don't fire all the weapons off at once every day.

It is worth noting that my list of 19 might not be the end-all be-all list
for all of humankind for all application-spaces/problem-spaces. They are the 19
which I see as generally applicable throughout coarse-grained-MT realtime
embedded-systems composed of one or more canonical Von Neumann sequential
control-flow processors. I suspect that massively-parallel concurrency for
finite-element analysis using data-flow nonVon optical computers might have
their own batch which may be a superset of my 19 or, even more likely, not much
in common with my 19.

> Both approaches may very well end up with the
> similar solutions but at different costs (e.g. reliability, robustness,
> speed, proof, .). I am sure that the bottom-up approach can deal with many
> of your idioms. Furthermore, the results of the top-down approach are not
> very WYSIWYG to me and easily results in discontinuities between design and
> implementation.


The idioms/patterns are based on prior established-practice over the past 3
decades in the realtime embedded systems multithreaded software industry. By
thinking along the lines of time-proven prior art, I do not risk an architecture
or a high-level design which cannot be implemented, because, if I do not like my
current inventory of 19 idioms/patterns, I invent another one or two or three
which suit that problem-space even better. But the need to extend my set of MT
idioms does not occur very often, since my existing 19 are so expressive and so
mainstream.

> I advocate the bottom-up approach for my entire design and sometimes a
> top-down approach for lower-level implementation issues.


bottom-up from scratch:
When it comes to household products, do you make all of your own household
products from scratch at home in your shed out back? Butcher your own meat?
Make your own soap? Weave your own cloth from wool that you shaved or cotton
that you picked?

bottom-up from scratch:
When it comes to entertainment, do you write your own plays, your own music,
your own books in genres of your own invention with you, your family, and your
friends performing the entertainment themselves?

bottom-up:
When deciding what to eat do you first go to your vitamin bottles (the
necessary & sufficient minimal set of nutrition), and then build a meal around
the vitamins, thinking first & foremost about the vitamins?

> The breadth &
> variety of MT is something I do not need when I design a program.


top-down shopping for idioms:
Or for household goods, do you go shopping at a retail store which has a
breadth & variety of previously-established product-lines which have shown to be
useful to a variety of people in a variety of situations. Prepackaged cuts of
meat appropriate for one meal. Prepackaged bars or bottles of soap for use at
one wash basin. Already-sewn clothes from already-woven fabric.

Just because Walmart has a million products on its shelves, does not mean you
are not required to buy out Walmart's entire inventory nor buy one of each
product. The nice thing is that you have the freedom to choose between multiple
useful already-made idioms/patterns/products and the freedom to change your mind
on future shopping trips.

top-down shopping for idioms:
Or for entertainment, do you:
1) go to one of your local cinemas which together have a breadth & variety of
already-produced films from which you can choose a movie of a particular
genre/idiom/pattern, ignoring the rest of the breadth & variety for the moment?
2) go to one of your local music venues which together have nearly every
style of live music from which you can choose an already-rehearsed performance
of a particular genre/idiom/pattern, ignoring the rest of the breadth & variety
for the moment?
3) go to one of your local stores which has a breadth & variety of
already-produced books or compact-discs from which you can choose a particular
genre/idiom/pattern, ignoring the rest of the breadth & variety for the moment?

top down:
Or for meal planning, do you first think which foods you would like to eat
(e.g., I would like meat at this meal. I would like some carbohydrates. I
would like some sort of salad. I would like some form of liquid to drink.)
followed by checking the pantry to see which already-purchased food-products can
implement this meal architecture? If the pantry's inventory is insufficient,
you may go to the store or garden and go shopping for even more
already-established food idioms/patterns/products.

I think that it is obvious to all people living in the industrialized world
that having a store of already-made products which appeal to each
genre/idiom/pattern is not only commonplace but highly advantageous.

Furthermore, people shop at retail stores in a top-down fashion every day.
They start out with broad idioms/patterns which they implement/satisfy in
drill-down top-down fashion. For example, I need to buy meat at the grocery
store (a broad meal-architectural goal). Upon further reflection about my
problem-space, I realize that I need a nice large delicious cut of meat for the
dinner-party which I have planned. I go to the refrigerated/fresh meat
department take a look around and/or the frozen-meat freezers. Once at the meat
display, I see that certain kinds of meat for sale, say, 19 kinds of meat
including ones which I do not interest me for a dinner party: hot dogs, tripe,
and so forth. Then I make my selection to buy a leg of lamb based on my needs
in that context, verifying that that idiom/pattern/cut-of-meat is available,
supported, and in-stock.

> MT in
> design is hazardous and inherently complex. There are better ways to start
> with.

MT is especially hard if one reinvents the wheel from scratch every time
instead of starting with time-proven already-established prior art:
long-standing idioms/patterns used in real-time embedded systems, which has been
using MT for multiple decades in industrial practice.

Hillie

unread,
May 26, 2002, 10:59:55 AM5/26/02
to
"Mark Johnson" wrote:

> Gerald Hilderink wrote:
> >
> > "Daniel Miller" wrote :
> >
> > > There are two perspectives regarding multithread programming:
> > > 1) bottom up
> > > 2) top down.
> > > [very nice explanation snipped]
> > Your top-down approach gives people a very good reason not to use
> > multithreading, since it makes life too complex, i.e. complex in
reasoning,
> > complex in implementing, no formal foundation, and it goes beyond the
> > primary focus.
> As a "top down" kind of guy, I must disagree. Perhaps it is a side
> effect of how I was trained (in school and at my company), but one of
> the first things I start off with is a context diagram. What is "inside
> the system", what is "outside the system", and the interface between
> them. That is key information required to bound the scope of the system
> being implemented. You can then do a top-down decomposition / bottom-up
> implementation of the system. There are several books on the shelf
> behind me that describe this for "structured analysis" or "object
> oriented" approaches.


Hmm, there is a misunderstanding here. From a software design of view I am
also a "top-down" kind of guy. Therefore I agree with you.

I interpreted Daniel's "bottom-up" and "top-down" definitions in the context
of programming paradigm and not in the context of software design. His
statements could explain the different design motivations behind, for
example, Ada and C++.

One could consider Ada, occam, Limbo, Handel C as "bottom-up" programming
languages and these languages can be used within "top-down" design
approaches, as in Yourdon, Hatley/Birbhai, or Ward/Mellor . Therefore, I am
not very happy with Daniels statements since they can be easily in
contradiction.

> > Look around us...describing our real world in the top-down approach is
hard,
> > if not impossible.
> I disagree.


Ah, ok, I was talking about expressing requirements in terms of a few
abstract primitives and not really about the design itself.

Expressing our real-world in abstract terms of processes (or tasks), events,
communication and objects is, for me, simpler and more natural than
expressing the world in terms of threads and a variety of thread
synchronization constructs. The terms of processes (or tasks), events,
communication and objects form the ingredients for my design. Threads and
thread synchronization are too much about implementation issues and this
paradigm troubles maintaining a clear overview of the design. This is the
same problem with the threading model in the UML. The threading model causes
discontinuities between the different diagrams and a good overview of
concurrency is easily lost.

> > I advocate the bottom-up approach for my entire design and sometimes a
> > top-down approach for lower-level implementation issues. The breadth &
> > variety of MT is something I do not need when I design a program. MT in
> > design is hazardous and inherently complex. There are better ways to
start
> > with.
> Again, many people are trained the other way and have built plenty of
> systems in a top down manner with success. As you note - top down does
> work in certain situations. Also, MT designs can be very simple but
> exhibit complex behavior (the aerodynamic example above). It depends on
> what you choose to implement and how you do it. You should use the right
> tool for the right job (and not just a hammer on every nail and screw...
> :-)).

Yes. My experience is that discribing complex behavior is not so simple in
MT; only for simple behaviors

I think that most of us are "top-down" kind of guys when is comes to
designing software. The choice of concurrency paradigm can be different from
the choice of design approach; I rather do not prefer MT. This is perhaps
why I did misinterpret Daniel's statements.

Thanks,

Gerald.

Hillie

unread,
May 26, 2002, 12:37:32 PM5/26/02
to
"Daniel Miller" wrote:

> Your line of reasoning appears to conflict internally with itself.
>
> On one hand you seem to be arguing against idioms and patterns
altogether.
> Rather you seem to be arguing for a bottom-up approach as defined by me
along
> this thread, not as defined in any prior art. Do you realize which
> ramifications your line of reasoning leads to? By arguing for the
bottom-up
> approach, you would start with the thread-synchronization primitives as a
> mandate, then contort an architecture to best fit the restricted
solution-space
> which was determined a priori. This bottom-up perspective of
> thread-primitives-contaminate-architectural-decisions appears to directly
&
> thoroughly conflict with your "primary focus ... on the application
> (analysis/requirements/design)". Based on what you have written in your
> posting, I think that you are top-down, but just don't realize it yet.

As I explained to Mark Johnson as a reply on his message, there is a


misunderstanding here. From a software design of view I am also a "top-down"
kind of guy. Therefore I agree with you.

When I read your definition about "bottom-up" and I immediately thought
about CSP based programming languages, like Ada and occam. These languages
contain a recommended minimum set of thread-synchronization-primitives, like
channels, protected objects, and compositional constructs, ALTs, PARs, SEQ,s
PRIPARs, and PRIALTs. This fits the profile of bottom up, which I reprinted
below. This is the programming paradigm I use for developing high
reliability safety critical real-time systems from a "top-down" approach.

" The bottom up perspective tends to focus on identifying a recommended
minimum
set of thread-synchronization primitives which are necessary and sufficient
for
all points of usage. Once such a necessary & sufficient minimum set of
thread-synchronization primitives has been established, then push the
frontier
of thought upward to application-domain to educate how the minimum set of
thread-synchronization primitives can be successfully applied."

Your definitions for "bottom-up" and "top-down" could explain the different
design motivations behind, for example, resp. Ada and C++ with MT. Therefore
I interpreted your "bottom-up" and "top-down" definitions strictly in the
context of these different programming paradigms and not in the context of
software design.

The occam razor went through my mind, if you know what I mean? :-). This
basically means that you use those things you really need and leave things
out you don't need, which could be interpreted as "bottom-up" in your
definition. I guess, this could be interpreted as "top-down" as well, hmmm.

Nevertheless, I appreciate your (long but nice) reply :-). I hope you
understand the source of misunderstanding at my side :-).

I have added a few comments below.


> > The bottom-up approach provides abstract notion about
> > processes, events, and communication, in which we think about systems in
a
> > natural way.
>
> I cannot speak for what is natural for you, but to start with a
restricted
> minimal set of thread-synchronization primitives is abhorrently unnatural
for
> me. (Ultimately the minimal set of thread-synchronization primitives on
> uniprocessors is: the test-and-set instruction or noninterrupted
equivalent
> atomic sequence of instructions; that is where the most-pure bottom-up
person
> would start.)

Hehe, from a design point of view processes, events, and communication will
used in a "top-down" manner, of course.

> As one can see, this drill-down of further & further refinement (which
I call
> top-down on this thread) is very natural for at least this human being
(i.e.,
> me) and probably thousands upon thousands of others if the popularity of
> software engineering, OO, patterns, and idioms in our industry is any
guide. In
> fact it appears to be quite natural to you too based on your desire to
start at
> the analysis-time application-layer/problem-space to progress downward
instead
> of the coding-time thread-synchronization primitive layer/solution-space
to
> impose a technocratic solution in boilerplate fashion on the
problem-space.
>
> > Then a small set of fundamental synchronization primitives can
> > be used to realize this.
>
>
> Ahh! You think that I use all 19 in every unit of software that I
write. No
> no no, these 19 form my minimal set of weapons that I expect to have in my
> arsenal in case I need them. I don't fire all the weapons off at once
every day.

Hehe, of course not :-).

I think that CSP offers you about 5 minimal set of weapons in its arsenal.
Each element in the set can be futher refined.

1. channels (refinements -> primitive channels, call channel, partially or
non-blocking channels, links)
2. PAR (refinements -> round-robin PAR, PRIPAR)
3. SEQ
4. ALT (refinements -> fair ALT, PRIALT).
5. guards (refinements -> conditional guard, timeout guard, skip guard,
...)

> > MT in
> > design is hazardous and inherently complex. There are better ways to
start
> > with.
>
> MT is especially hard if one reinvents the wheel from scratch every
time
> instead of starting with time-proven already-established prior art:
> long-standing idioms/patterns used in real-time embedded systems, which
has been
> using MT for multiple decades in industrial practice.

Of course, CSP constructs are such long-standing idioms/patterns used in
real-time systems, which has been using MT (although hidden for the user)
for multiple decades in industrial practice. These are based on a
mathematical and very-well thought-out foundation. Furthermore, MT is not
compositional and not object-oriented, whereas CSP is! My point is that MT
is not only way to deal with high reliability safety critical real-time
systems.

I think that I begin to realized (thanks to this discussion) that the CSP
approach can be associated with all "bottom-up", "top-down", and also
"middle-out" approaches. This is becoming more and more interesting :-).


Thank you and I appreciated your reply,

Gerald Hilderink.


t...@cs.ucr.edu

unread,
May 29, 2002, 11:42:37 AM5/29/02
to
Mark Johnson <mark_h_...@raytheon.com> wrote:
[...]
: Semaphores (counting or not)

: provide a specific synchronization mechanism. If your application DOES
: fit that mechanism, you should use it. If not, then don't.

Semaphores and mutexes+conditions can solve exactly the same
coordination problems (provided that we ignore some of the condition
embellishments added by posix). The issues have to do with style and
perhaps efficiency.

: You are going to have a hard time trying to convince me that posix


: mutexes and condition variables provided with glibc will satisfy the
: needs of our application.

AFAIK, there are are both user-mode and kernel-based implementations
of both coordination mechanisms (i.e., of semaphores and of
mutexes+conditions). The user-mode mechanisms work only to coordinate
threads within a given process. Interprocess coordination requires
kernel-based mechanisms.

It sounds like you are comparing kernel-based semaphores with
user-mode mutexes+conditions. (In which case, I agree that they
cannot do the same things.)

: In the current series of code reviews we are


: doing, we have found more problems with unsafe coding without the
: semaphores (or cache flushes to ensure serialization) than we do with
: them.

I'm not surprised! ;-)

Tom Payne

Alexander Terekhov

unread,
May 29, 2002, 12:29:07 PM5/29/02
to

t...@cs.ucr.edu wrote:
>
> Mark Johnson <mark_h_...@raytheon.com> wrote:
> [...]
> : Semaphores (counting or not)
> : provide a specific synchronization mechanism. If your application DOES
> : fit that mechanism, you should use it. If not, then don't.
>
> Semaphores and mutexes+conditions can solve exactly the same
> coordination problems (provided that we ignore some of the condition
> embellishments added by posix). The issues have to do with style and
> perhaps efficiency.

and perhaps *ISOLATION* (in favor of semas... and
signaling [posting] from async.signals/interrupts
handlers aside, I mean):

http://groups.google.com/groups?selm=Jkta8.51%241h5.372%40news.cpqcorp.net
(Subject: Re: pthreads vs. IPC: what to use when?)

"....
b) With processes, each "entity" is an isolated security domain. Failures
in one process don't affect another directly, and the communication
channels (IPC) can be monitored and controlled to avoid contamination from
a failing entity. This can be powerful for servers that need to operate in
multiple security domains or need reliability. (Some have complained that
POSIX mutexes don't allow a locking thread to detect that the previous
owner terminated "abnormally"... that's because it wouldn't do any good to
know without isolation between the entities involved. With IPC mechanisms
it makes sense to know, because you can do something about it.)
...."

regards,
alexander.

Alexander Terekhov

unread,
May 29, 2002, 4:46:17 PM5/29/02
to

I'd like to 'move' it back to c.p.t, so to speak. ;-)

Daniel Miller wrote:
>
> Inclusion of comp.std.c++ is due to my discussion below regarding how the
> Boost community has been (and continues to propose) going in the wrong direction
> with respect to Boost.threads' omission of the following mechanisms: semaphore,
> multiproducer-multiconsumer message-queues, and thread-selection-by-kernel
> pool-allocation. This whole topic came up on comp.programming.threads, but
> applies as well to what the content of the multithread capabiltiies of C++ are
> to be in C++0x.

> Viewpoints such as the posting quoted below parallels the mistakes made
> within the Boost community regarding the intential removal of semaphores from
> their Boost.threads library. Although suggestions to remove semaphore from the
> original poster's design are warranted, the posting quoted below instead rails
> hard against all usage of semaphore presumably throughout the entire software
> industry. No thank you! For those readers who wish to hear an opposing
> positive treatment regarding the usefulness of semaphores, please read my recent
> posting to comp.programming.threads:
>
> http://groups.google.com/groups?hl=en&selm=3CD1864A.10401%40tellabs.com&rnum=9
>
> or the whole thread in context
>
> http://groups.google.com/groups?hl=en&threadm=2e53duk57rgfptgh684f01olnm3e5u69v9%404ax.com&rnum=1&prev=/groups%3Fq%3DDaniel%2BMiller%2Bgroup:comp.programming.threads%26hl%3Den%26selm%3D2e53duk57rgfptgh684f01olnm3e5u69v9%25404ax.com%26rnum%3D1
>
> Or read about real-time embedded programming in general, especially from the
> multithreaded asynchronous message-queue school of thought embraced by most
> RTOSes (most notably: pSOS+ and VxWorks).
>
> And/or read onward:


>
> > The semaphore "solution" doesn't really apply cleanly to anything, not
> > even the fabled single producer / single consumer problem.
>

> First of all, for readers who might be entertaining such broadly
> anti-semaphore claims, it is not a fable. The producer-consumer mechanism has
> been used for decades as a part of embedded software. The canonical approach to
> the producer-consumer mechanism in the RTOS community is called a message-queue,
> which acts as a conveyor-belt of sorts, such as between threads within the same
> address-space or between processes/separate-address-spaces with shared memory.
> Fully leveraging this conveyor-belt analogy in an MT-software
> design/architecture typically provides the opportunity for clean & complete
> hand-off of a unit-of-work from one thread to another or from one thread out of
> many to a kernel-selected thread within a loose pool of threads (where "pool of
> threads" is defined to be one or more threads pending on a single message-queue).
>
> Secondly again for readers who might be entertaining such broadly
> anti-semaphore claims, "single producer / single consumer" misrepresents the
> topic. When one models the producer-consumer mechanism with a semaphore, one
> does not get a *single-thread* producer to *single-thread* consumer mechanism,
> one gets a *one-or-more-thread* producer to *one-or-more-thread* consumer
> mechanism which can be highly useful for interthread hand-off of units-of-work
> to load-sharing pools of threads. When a semaphore models an interthread
> message-queue mechanism:
> 1) multiple threads may post to the same message-queue and
> 2) multiple threads may pend on the same message-queue.
>
> The former is a wonderful way for multiple producer-threads to submit
> units-of-work which are off-topic in their mission to some message-queue that
> feeds a pool of threads whose mission it is to perform that category of
> unit-of-work. The latter is a wonderfully-efficient low-overhead load-sharing
> thread-pool mechanism where the scheduling of threads is done (implicitly) via
> thread-selection in the kernel-layer instead of via a manually-written
> less-efficient God-controller in user-layer. Unfortunately all of this
> real-time embedded software-architectural elegance is apparently lost on people
> who subscribe to the overly-academic anti-semaphore viewpoints, because they do
> not focus on how the producer-consumer/message-queue mechanism fits into a
> robust, stable, useful overall *asynchronous* architecture for multithreaded
> software, such as real-time embedded systems---e.g., telephone equipment,
> datacom equipment, high-availability servers, postal equipment, nuclear power
> plants, aircraft, marinecraft, military vehicles, military weapons.


>
> > Unless of
> > course you never want to shut it down. If you did want it to shut
> > down you could add a flag and check it after the sem_wait(). Kludgey,
> > but not too horribly kludgey. But you don't get clean shutdown that
> > way, just abort shutdown since you don't know whether you've processed
> > all the buffers or not, not without some really kludgey logic.
>

> Once again for readers who might be entertaining such broadly
> anti-semaphore claims, "you don't get clean shutdown" misrepresents the topic.
> When wanting to shutdown a message-queue (the canonical producer-consumer
> mechanism in real-time software) one simply posts a shutdown message to the
> message-queue which is enqueued in FIFO order behind all priorly-posted requests
> for units-of-work/messages. Shutdown is a valid nonarcane behavior for a
> message-queue, and thus can be considered part of the primary mission of a
> message-queue and thus can be part of the public interface of such a
> message-queue class. Upon dequeuing a shutdown request, the message-queue emits
> to all pending threads some form of don't-pend-on-me-anymore-I-am-going-away
> indicator (e.g., return code or exception, depending on local design's taste).
> Alternatively in certain designs, the shutdown message might be processed by
> awoken thread which was pending on the queue. In either case: no kludge, just
> expected, squarely-within-stated-mission behavior: make sure that all
> already-queued units-of-work are permitted to be drawn down.
>
> Likewise, if a semaphore is used to model permission-to-allocate from a pool
> of limited resources, shutdown has an equally clean & robust solution. Either
> this application of semaphore can likewise have an explicit public shutdown
> behavior which suppresses further allocation from the pool (because graceful
> shutdown would imply that the use of the pool has reached quiescence: no member
> of the pool is in use). Or considering a more garden-variety semaphore, the
> thread requesting the shutdown requests n resources (i.e., makes n one-resource
> blocking-requests serially) so that the software accomplishing the graceful
> shutdown hogs all n resources in an n-sized pool to assure that none are in use.
> Again no kludge, semaphore is working smoothly as designed & applied
> enforcing the quiescence which is part of the graceful shutdown: make sure that
> no member of the pool is in use.


>
> > If you deconstruct the XRAT (design rationalization) for semaphores,
> > you can surmise that somebody thought that semaphores could be
> > implemented that more efficient than condition variables,
>

> If the reader were to obediently comply with such line of reasoning here, the
> reader might think that a producer-consumer RTOS-style message-queue can be
> implemented (nearly-)equally efficiently either via a semaphore or via a
> condition-variable. Let's see if such apparent claims bear out by using POSIX
> semaphores & POSIX condition-variables.
>
> Before proceeding, please read the following sections from the POSIX standard
> now:
>
> http://www.opengroup.org/onlinepubs/007904975/functions/pthread_cond_signal.html#tag_03_515_07
>
> (especially the 1st paragraph in the APPLICATIONS section)
>
> http://www.opengroup.org/onlinepubs/007904975/functions/pthread_cond_signal.html#tag_03_515_08
>
> (especially the 1st & 2nd paragraphs after the code in the RATIONALE section)
>
> One might use pthread_cond_broadcast for multiprocessors as suggested above
> within the POSIX standard. But this implementation would perform worse than
> semaphore on uniprocessors, because all pending threads would awake and evaluate
> their logical-predicate in the condition-variable implementation. If m threads
> are waiting for permission to acquire a resource and if only one resource is
> available for acquisition, then m-1 threads wasted their time with relatively
> expensive thread-switches if interthread-intraprocess or process-switches if
> interprocess-intraprocessor. Note that in the semaphore implementation the
> kernel would awake exactly one thread. In this case semaphore would be more
> efficient than condition-variable.
>
> One might use pthread_cond_signal to avoid this inefficiency on
> uniprocessors. As aluded to in the 1st paragraph of the APPLICATIONS section,
> this implementation would perform worse than semaphore on multiprocessors,
> because only one pending thread would run at a time even if more than one
> resource was available for acquisition. If m threads are waiting for permission
> to acquire a resource and if the multiprocessor has p processors where p >= m
> and if r resources come available for acquisition where r >= m, then a serial
> awaking of one thread at a time could occur where m threads could have awakened
> concurrently. Note that in the semaphore implementation the kernel could awake
> up to m threads concurrently. In this case semaphore would be more efficient
> than condition-variable.
>
> Furthermore semaphore *must* be used instead of condition-variable if the
> posting/incrementing/resource-now-available indicator is to originate from
> within an interrupt-style signal handler. For explanation read the 2nd
> paragraph of the pthread_cond_signal APPLICATIONS section at:
>
> http://www.opengroup.org/onlinepubs/007904975/functions/pthread_cond_signal.html#tag_03_515_07
>
> (espeically the 2nd paragraph in the APPLICATIONS section)
>
> Compare & contrast with no such restriction for semaphores:
>
> http://www.opengroup.org/onlinepubs/007904975/functions/sem_post.html


>
> > If you deconstruct the XRAT (design rationalization) for semaphores,
> > you can surmise that somebody thought that semaphores could be
> > implemented that more efficient than condition variables, and so
> > it might be useful to have that efficiency in case it could be
> > exploited. Semaphore are certainly not necessary. You can get
> > along fine without them.
>

> Why can't those people who hold anti-semaphore viewpoints, simply avoid
> using semaphores in their own software instead of attempting to engage in an
> industry-wide suppression of semaphores' correct&beneficial usage? Semaphores
> (as well as semaphores' canonical application to producer-consumer
> message-queues and thread-selection-by-kernel pool-allocation) are certainly
> useful, robust, efficient, and elegant in multithreaded software, especially in
> real-time embedded systems. Thus semaphores deserve to be part of C++0x's
> multithreaded feature-set. What I can get along fine without is the
> anti-semaphore/anti-message-queue/anti-pool-allocator viewpoints which seek to
> harshly exclude the long-established practices of real-time embedded software
> which is based on semaphores and message-queues. Likewise, because these
> viewpoints have dominated the Boost.threads library, I can get along fine
> without the current & proposed chronic limitations of the Boost.threads library
> which currently lacks semaphore, multiproducer-multiconsumer message-queues, and
> thread-selection-by-kernel pool-allocators and is intended to continue lacking
> these mechanisms.
>
> If these anti-semaphore viewpoints were merely a few lone voices at the
> fringes of the universe, I would simply ignore them. But these viewpoints have
> been steering the direction of Boost.threads which thinks that it is on track to
> become part of C++0x's standard libraries. (Egads!) Some of us in the
> real-time embedded systems world perceive the frontal assault on semaphores (and
> the related assault on message-queues which support multiple producers posting
> to a mesage-queue pended on by each member of pool of consumers) to be a direct
> threat to the applicability of C++0x's libraries to the real-time embedded
> software world. If the multithread model of C++0x or its libraries is contorted
> to the point which the MT-classes cannot (or do not directly) support
> time-honored real-time embedded real-time systems' multithread concepts
> (semaphores & multiproducer-multiconsumer message-queues), then C++0x would
> shutout a portion of its heritage: software to be embedded within telephone
> equipment. Remember that Bjarne Stroustrup worked for a telephone-equipment
> manufacturer when he evolved C into C++ [AT&T: both a telephone service provider
> but also a telephone equipment manufacturer at the time, now Lucent] and that a
> large motivation for the leanness & efficiency of C++ was to scale down to the
> same spaces that C plays well in, including embedded real-time systems,
> specifically onboard network elements in the telecommunications industry.


>
> > You should do your design using the more general mechanism, condition
> > variables, and then, if it lends itself to a semaphore solution without
> > too much contortion, and if the semaphore implementation actually is
> > in fact significantly more efficient, and if performance really is that
> > much of a critical issue, then by all means, go ahead and use semaphores.
> >
> > In the case of your problem a solution would be use some sort of data
> > structure, set, queue, priority queue, or whatever, to communicate to
> > OutThread which devices were ready to communicate with. You may be
> > using more than one mutex since there is the data structure itself
> > and data associated with each device such as a count.
>

> Once again, such viewpoints misrepresent the finer points of the topic. By
> focusing the solution heavily on mutexes (i.e., *synchronization* mechanism),
> such viewpoints divert the reader from easily seeing the primary purpose of the
> multiproducer-multiconsumer message-queues: Asynchronous interaction between
> threads, with emphasis on the "a" of asynchronous. Yes, the
> multiproducer-multiconsumer message-queue would need to protect itself extremely
> briefly during pushPost and popPend operations, but this would be within the
> internal operations of the message-queue itself, typically eliminating
> interthread synchronization when accessing the units-of-work conveyed by the
> message-queue. The application-domain would not need to protect the data which
> the message-queue is conveying if the canonical rule regarding the use of
> message-queues were to be obeyed: the posting/pushing/producing thread
> relinquishes all rememberance of the data which it pushed into the message-queue
> and the pending/popping/consuming thread relinquishes all of its rememberance of
> the data which it popped from the message-queue. Just as mutexes & read-write
> locks are mechanisms of interthread *synchronization*, message-queues are a
> mechanism of *asynchronous* hand-off of units-of-work between threads.
>
> Rather than recognize that semaphores & the multiproducer-multiconsumer
> message-queue mechanism can be written once & for all as useful general-purpose
> infrastructure within a (standard) library, the
> antisemaphore/condition-variables-only viewpoint causes an erosion of
> OO-encapsulation which otherwise would be possible with a semaphore class.
> Instead of encapsulating the granting of permission to access a resource (i.e.,
> producer-consumer's produced resource; message-queue's posted/pushed message;
> pool's allocatable limited resource) inside a class named semaphore (or inside
> each of two classes named producer_consumer and pool_dispenser), this granting
> of permission to access a resource is inappropriately placed outside of the
> infrastructural (standard) library (layer-N) into the application-domain
> (layer-N+1) in a rather messy way. This
> condition-variable-with-predicate-evaluation-in-the-layer-N+1-application-domain
> violates my "Are the guts hanging out?" test of whether a design violates
> OO-encapsulation.
>
> Furthermore, the thread-selection-by-kernel allocation-from-pool mechanism
> has a corresponding deallocation-back-to-pool behavior. Leveraging the C++
> addage "resource allocation on ctor, resource deallocation on dtor" for
> exception-safety, the pool_dispenser class would have a guard class whose ctor
> acquired permission to access a member of the pool and whose dtor released
> permission to access a member of the pool. Because the condition-variable
> solution has violated OO-encapsulation, there is no ctor for
> permission-acquisition nor any dtor for permission-release. Thus there is less
> exception-safety with the condition-variable approach. Thus there is the
> potential for quite harmful resource leaks in the condition-variable approach
> which is not possible with the semaphore/pool_dispenser approach with its
> accompanying guard class.
>
> One likes to get dial-tone fast when picking up the telephone handset,
> correct? One likes for the telephone switch in one's community to handle
> periods of heavy loads without loss of service, correct? One likes for the
> weaponry of one's military to aim & fire rapidly in real-time, correct? One
> likes for one's air-traffic control systems (or the airplane's control systems)
> to operate with low-latency in real-time, correct? Building *asynchronous*
> (with the emphasis on the "a") embedded real-time systems goes a long way toward
> accomplishing those goals and has for decades. Focus less on
> interthread/interprocess *synchronization* and more on clean producer-consumer
> hand-off mechanisms enabling thread/process *asynchronization" and one will tend
> to have an MT-software-system which has higher sustained throughput even under
> heavy loads.
>
> Please ensure that C++0x supports mechanisms for *asynchronous* hand-off of
> units-of-work between threads via multiproducer-multiconsumer message-queues as
> much as it supports mechanisms for interthread *synchronization*.


>
> > So OutThread logic is going to look something like
> >
> > while (outbound data) {
> > while (ready devices) {
> > ...
> > }
> > }
> >
> > which translated into CV logic
> >
> > while (outbound data) {
> > pthread_mutex_lock();
> > while (no ready devices) {
> > pthread_cond_wait();
> > }
> > ...
> > pthread_mutex_unlock();
> > ...
> > }
> >
> > Joe Seigh
>

> <glossary>
>
> RTOS = real-time operating system
>
> MT = multithread(ed)
>
> Message-queue = In this context all references to message-queue are
> leveraging a conceptual C++ extrapolation of pSOS+'s interthread message-queues.
> Note that these message-queues differ from POSIX or System V message-queues in
> that a POSIX/System-V message-queues dictate a message-queue-buffer/payload
> structure, whereas pSOS-style message-queues are a conveyor for *any* type
> (generally, a pointer to any type versus a single integer in pSOS)
>
> ---
> [ comp.std.c++ is moderated. To submit articles, try just posting with ]
> [ your news-reader. If that fails, use mailto:std...@ncar.ucar.edu ]
> [ --- Please see the FAQ before posting. --- ]
> [ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]

t...@cs.ucr.edu

unread,
May 29, 2002, 10:38:01 PM5/29/02
to
Alexander Terekhov <tere...@web.de> wrote:

Isolation is an orthogonal issue. As I have already pointed out
already, one can have ether user-mode or kernel-based implementations
of either mechanism, i.e., of semaphores or mutexes+conditions.
Coordinating threads that are isolated in separate processes (address
spaces) requires the use of kernel-based mechanisms.

Tom Payne

Mark Johnson

unread,
May 30, 2002, 9:37:48 AM5/30/02
to
t...@cs.ucr.edu wrote:
>
> Alexander Terekhov <tere...@web.de> wrote:
> [snip - isolation & coordination problems]

>
> Isolation is an orthogonal issue. As I have already pointed out
> already, one can have ether user-mode or kernel-based implementations
> of either mechanism, i.e., of semaphores or mutexes+conditions.
I agree with this part.

> Coordinating threads that are isolated in separate processes (address
> spaces) requires the use of kernel-based mechanisms.
>

Hmm. That restriction is not true if you allow the user mode
implementation to share memory between processes. A mechanism we are
using basically has a shared memory block at address "X" in process A,
and address "Y" in process B. The semaphore "S" is at some offset O from
the beginning of the shared memory block. A will refer to it at address
X+O, B will refer to it at address Y+O. (and both manipulate the same
hunk of memory to implement the semaphore)

I am not saying that use of a kernel based mechanism is better or worse,
just that you don't HAVE to use a kernel based mechanism between
processes w/ separate address spaces.
--Mark

Andy Moreton

unread,
May 30, 2002, 9:56:30 AM5/30/02
to
mark_h_...@raytheon.com (Mark Johnson) wrote in <3CF62B2C.B1FE1B92
@raytheon.com>:

Not entirely true - you are relying on each thread having a coherent view of
that memory. For some architectures this will be true; for others you will
need memory barriers or a kernel primitive.

AndyM

--
GlobespanVirata, Unit 230 Science Park, Milton Road, Cambridge CB4 0WB, UK
http://www.globespanvirata.com/ Tel: +44 1223 707400 Fax: +44 1223 707447

Mark Johnson

unread,
May 30, 2002, 5:20:19 PM5/30/02
to
Andy Moreton wrote:
> [snip]

> Not entirely true - you are relying on each thread having a coherent view of
> that memory. For some architectures this will be true; for others you will
> need memory barriers or a kernel primitive.
>
Having implemented such a mechanism - I agree. The example I made left
out all the "interesting" stuff required when you don't have a cache
coherent view of memory.

In a recent code review, the simple (coherent memory) case was about
three lines of code, the more complex (which required calls to a
"sequence" function) case was over a dozen. However, the mechanism for
that memory barrier or "sequence" (as called by this one driver) does
not necessarily require kernel support. It more likely depends on an
instruction sequence available from user code.
--Mark

Alexander Terekhov

unread,
May 31, 2002, 6:44:26 AM5/31/02
to

But you can't really {fully} 'resolve' isolation 'issues' with
mutexes and condvars; PROCESS_SHARED, I mean (unless I'm missing
something). You really need semas for that. That was my point.

regards,
alexander.

t...@cs.ucr.edu

unread,
May 31, 2002, 4:59:54 PM5/31/02
to
Alexander Terekhov <tere...@web.de> wrote:
[...]
: But you can't really {fully} 'resolve' isolation 'issues' with

: mutexes and condvars; PROCESS_SHARED, I mean (unless I'm missing
: something). You really need semas for that. That was my point.

It's easy enough to implement semaphores via mutexes and conditions.
But you knew that, so obviously I'm missing your point. ;-)

Tom Payne


Alexander Terekhov

unread,
May 31, 2002, 5:45:13 PM5/31/02
to

How would you implement/emulate PROCESS_SHARED/IPC semaphores...
*capable* to 'survive' all kinds of process abends (*before*
releasing the mutex cases including)? Mutexes and condvars
'presume' that you have/use 'unprotected' shared memory between
threads (whether it's inter- or intra-process does NOT really
matter). As long as you have/introduce such thing you are pretty
much loosing on {true} 'isolation'... unless I'm just missing
something here (as usual ;-)). Also, somewhat related, I think:

http://groups.google.com/groups?threadm=3C92063F.CCA60952%40web.de
("Subject: Re: Question about persistence of pthread_rwlock_t" subthread)

regards,
alexander.

David Schwartz

unread,
May 31, 2002, 6:24:13 PM5/31/02
to
Alexander Terekhov wrote:

> How would you implement/emulate PROCESS_SHARED/IPC semaphores...
> *capable* to 'survive' all kinds of process abends (*before*
> releasing the mutex cases including)?

How do you protect against one process that just messes with the
semaphore by performing random operations on it?

> As long as you have/introduce such thing you are pretty
> much loosing on {true} 'isolation'... unless I'm just missing
> something here (as usual ;-)). Also, somewhat related, I think:

If you create shared memory, you create a deliberate break in the
isolation. If you can't afford the break, don't create the window and
use something secure (like pipes) instead. Semaphores are inherently
unsafe in that you allow another process to cause you to block.

DS

Alexander Terekhov

unread,
Jun 1, 2002, 9:34:47 AM6/1/02
to

David Schwartz wrote:
>
> Alexander Terekhov wrote:
>
> > How would you implement/emulate PROCESS_SHARED/IPC semaphores...
> > *capable* to 'survive' all kinds of process abends (*before*
> > releasing the mutex cases including)?
>
> How do you protect against one process that just messes with the
> semaphore by performing random operations on it?

Uhmm. What exactly do you mean... 'random' lock/unlock/setval operations?

> > As long as you have/introduce such thing you are pretty
> > much loosing on {true} 'isolation'... unless I'm just missing
> > something here (as usual ;-)). Also, somewhat related, I think:
>
> If you create shared memory, you create a deliberate break in the
> isolation. If you can't afford the break, don't create the window and
> use something secure (like pipes) instead. Semaphores are inherently
> unsafe in that you allow another process to cause you to block.

Still, SEM_UNDO/semadj aside, [using IPC over semas] yet another
'process' (thread(s) -- some recovery/watchdog/ruler/suspect-killer/
whatever-you-like-to-call-it 'mechanism') IS ABLE TO UNBLOCK those
who deserve it ('kill' others ;-)) and bring things back in-order,
so to speak.

That does NOT really work with mutexes and condvars. Oder? ;-)

regards,
alexander.

t...@cs.ucr.edu

unread,
Jun 1, 2002, 11:25:56 AM6/1/02
to
Alexander Terekhov <tere...@web.de> wrote:

: David Schwartz wrote:
[...]
:> If you create shared memory, you create a deliberate break in the


:> isolation. If you can't afford the break, don't create the window and
:> use something secure (like pipes) instead. Semaphores are inherently
:> unsafe in that you allow another process to cause you to block.

: Still, SEM_UNDO/semadj aside, [using IPC over semas] yet another
: 'process' (thread(s) -- some recovery/watchdog/ruler/suspect-killer/
: whatever-you-like-to-call-it 'mechanism') IS ABLE TO UNBLOCK those
: who deserve it ('kill' others ;-)) and bring things back in-order,
: so to speak.

: That does NOT really work with mutexes and condvars. Oder? ;-)

It's probably impossible to implement semaphores that have all
possible robustness embellishments using kernel-based mutexes and
convars. In my limited experience, however, generalized recovery
mechanisms are usually not sufficient --- if something goes wrong it's
time to roll all participants back to known "good" states and start
over. Kernel-based convars and mutexes should have time-outs, which
should be sufficient to accomplish such restarts.

Tom Payne

Alexander Terekhov

unread,
Jun 1, 2002, 12:28:24 PM6/1/02
to

Time-outs won't help with respect to 'abendoned' [?'abandoned'?]
mutexes, to begin with.

regards,
alexander.

David Schwartz

unread,
Jun 1, 2002, 3:59:08 PM6/1/02
to
Alexander Terekhov wrote:
>
> David Schwartz wrote:
> >
> > Alexander Terekhov wrote:
> >
> > > How would you implement/emulate PROCESS_SHARED/IPC semaphores...
> > > *capable* to 'survive' all kinds of process abends (*before*
> > > releasing the mutex cases including)?
> >
> > How do you protect against one process that just messes with the
> > semaphore by performing random operations on it?
>
> Uhmm. What exactly do you mean... 'random' lock/unlock/setval operations?

You are saying that certain types of semaphore implementations allow a
windows where one process can interfere with the operation of another.
I'm saying that this is inherent to process-shared semaphores and
there's nothing you can do about it.

> > > As long as you have/introduce such thing you are pretty
> > > much loosing on {true} 'isolation'... unless I'm just missing
> > > something here (as usual ;-)). Also, somewhat related, I think:
> >
> > If you create shared memory, you create a deliberate break in the
> > isolation. If you can't afford the break, don't create the window and
> > use something secure (like pipes) instead. Semaphores are inherently
> > unsafe in that you allow another process to cause you to block.

> Still, SEM_UNDO/semadj aside, [using IPC over semas] yet another
> 'process' (thread(s) -- some recovery/watchdog/ruler/suspect-killer/
> whatever-you-like-to-call-it 'mechanism') IS ABLE TO UNBLOCK those
> who deserve it ('kill' others ;-)) and bring things back in-order,
> so to speak.

Maybe, maybe not. What if one of the others forks faster than the
killer can kill it?



> That does NOT really work with mutexes and condvars. Oder? ;-)

I grant that some implementations can provide more isolation than
others. But fundamentally, mutexes, condvars, and semaphores can't
provide as much isolation as pipes and sockets can.

DS

t...@cs.ucr.edu

unread,
Jun 1, 2002, 10:24:50 PM6/1/02
to
Alexander Terekhov <tere...@web.de> wrote:
[...]
: Time-outs won't help with respect to 'abendoned' [?'abandoned'?]
: mutexes, to begin with.

Why not?

Tom Payne

Alexander Terekhov

unread,
Jun 3, 2002, 2:52:02 AM6/3/02
to

Because other than 'killing everyone affected out there'
followed by 'suicide' w.r.t. yourself with subsequent
'recovery' (cleanup/restart... hopefully HOT -- from the
state recorded at the last 'good' check point) driven by
some higher level 'recovery' system/mechanism, you can't
really do anything at all, AFAICT.

regards,
alexander.

0 new messages