Robert Dewar's great article about the Strengths of Ada over other langauges in multiprocessing! - ADA
This is a discussion on Robert Dewar's great article about the Strengths of Ada over other langauges in multiprocessing! - ADA ; This paper:
http://www.aristeia.com/Papers/DDJ_J...04_revised.pdf
describes some of these issues in a C++ context and is written by two
authors who probably know what they are talking about. Their conclusion
is that it is pretty much impossible to write correct multi-threaded
code ...
-
Re: Robert Dewar's great article about the Strengths of Ada overother langauges in multiprocessing!
This paper:
http://www.aristeia.com/Papers/DDJ_J...04_revised.pdf
describes some of these issues in a C++ context and is written by two
authors who probably know what they are talking about. Their conclusion
is that it is pretty much impossible to write correct multi-threaded
code in C++ without (non-standard) compiler assistance. I'm paraphrasing
here. It is my understanding, however, that this matter will be
addressed in C++ 0x.
Peter
-
Re: Robert Dewar's great article about the Strengths of Ada overother langauges in multiprocessing!
On Mar 13, 5:40 am, Maciej Sobczak <see.my.homep...@gmail.com> wrote:
> On 13 Mar, 00:54, gp...@axonx.com wrote:
>
> > You are replying on posts without reading them carefully. The issue
> > is covered in the thread below:
>
> >http://www.codeguru.com/forum/archiv.../t-442321.html
>
> Unfortunately, most of the participants have no idea about the subject
> (they even admit it), so their discussion is not a good authority.
> The only exception there is Paul McKenzie, who actually claimed
> clearly that *volatile has nothing to do with threads*.
>
> There is a link to Microsoft documentation with example. This can be
> treated as an authoritative source of information related to Microsoft
> compilers *only* (and I have doubts even about this). Since the C++
> standard does not define the semantics of volatile in the presence of
> multiple threads, then any guarantee given by Microsoft should be
> treated only as *language extension*. In particular, the same code
> example will not work with other compiler.
>
> To be more exact, if Microsoft claims that their example works with
> their compiler, it means that references to volatile provide the
> release-acquire memory consistency, which in turn means that they
> involve memory barries. This is surprising, but let's check the
> assembly output from their compiler...
>
> OK, I've checked it with Visual Studio 2005 (I don't have access to
> anything newer).
> The generated code does *not* involve memory barriers. It will not
> work.
>
> A simpler example can explain the problem.
> Consider the following two variables:
>
> bool A = false; // can be as well volatile
> bool B = false; // can be as well volatile
>
> and two threads:
>
> // Thread1:
> A = true;
> B = true;
>
> // Thread2:
> if (B)
> {
> assert(A);
>
> }
>
> *From the point of view* of Thread1, only the following states are
> visible, as times goes on downwards:
>
> time 1: A == false && B == false
> time 2: A == true && B == false
> time 3: A == true && B == true
>
> In other words, from the point of view of Thread1, the following
> situation:
>
> A == false && B == true
>
> can *never* happen, because the order of writes just makes it
> impossible. In other words, the condition and assertion from Thread2
> would be correct if executed in Thread1.
>
> The problem is that Thread2 can see something different and there the
> assertion can fail. This can happen for two reasons:
>
> 1. If you write something to memory, you only instruct the CPU that
> you *want* something to be stored. It will do it - but not necessarily
> immediately and it can actually happen *some time later*.
> The problem is that if you store two values (separate store
> instructions), the CPU does not know that they are related - and can
> stored them physically in different order. The compiler has no control
> over it! It is the hardware that can reorder the writes to memory.
>
> 2. If you read something from memory, you can actually read something
> that is already in the cache - the value can be there already and
> *earlier*.
>
> Both these mechanisms can make Thread2 see different order of
> modifications than that perceived by Thread1.
> Again, the compiler has no control over it. It is all in hardware.
>
> This is also a reason for why the Double-Check Locking Pattern does
> not work. Please read this:
>
> http://www.cs.umd.edu/~pugh/java/mem...edLocking.html
>
> It describes the problem for Java, but mentions the same ordering
> issues.
>
> Don't use volatile for multithreading. It does not work.
>
> Note: Ada gives guarantees for proper ordering for volatile objects.
>
> --
> Maciej Sobczak *www.msobczak.com*www.inspirel.com
OK, your point well taken, so it is up to compiler vendors to
guarantee volatility under MT. Does it mean that original purpose of
volatile ma not always hold either?
G.
-
Re: Robert Dewar's great article about the Strengths of Ada over other langauges in multiprocessing!
Peter C. Chapin wrote:
> This paper:
>
> http://www.aristeia.com/Papers/DDJ_J...04_revised.pdf
>
> describes some of these issues in a C++ context and is written by two
> authors who probably know what they are talking about. Their conclusion
> is that it is pretty much impossible to write correct multi-threaded
> code in C++ without (non-standard) compiler assistance. I'm paraphrasing
> here. It is my understanding, however, that this matter will be
> addressed in C++ 0x.
>
> Peter
After reading the pointers given in this thread, I'm under the impression that
indeed you need to use volatile for unprotected variables accessed across
threads? For, example, in Ada:
declare
Global_Exit : Boolean := False;
-- pragma Volatile (Global_Exit);
-- pragma Atomic (Global_Exit);
begin
-- Lots o'tasks here that monitor Global_Exit for termination.
end;
Here you don't need a protected, since once someone makes Global_Exit true, the
end arrives and all is well. I would normally mark that as Atomic which, as it
implies volatile, is OK.
But let's say one knows that boolean is atomic for the architecture, and makes
the (risky) decision of not explicitly saying so to the compiler. I understand
that, without volatile, tasks never writing to Global_Exit could optimize away
any check for changes on it, and see it as a constant? (Indeed I guess Gnat
would issue a warning about Global_Exit being constant).
Although in Ada I don't see much (or any?) use for volatile, non-atomic shared
variables outside of protected objects.
Some flaw in my understanding?
-
Re: Robert Dewar's great article about the Strengths of Ada overother langauges in multiprocessing!
On Mar 13, 9:03 am, "Alex R. Mosteo" <devn...@mailinator.com> wrote:
> Peter C. Chapin wrote:
> > This paper:
>
> >http://www.aristeia.com/Papers/DDJ_J...04_revised.pdf
>
> > describes some of these issues in a C++ context and is written by two
> > authors who probably know what they are talking about. Their conclusion
> > is that it is pretty much impossible to write correct multi-threaded
> > code in C++ without (non-standard) compiler assistance. I'm paraphrasing
> > here. It is my understanding, however, that this matter will be
> > addressed in C++ 0x.
>
> > Peter
>
> After reading the pointers given in this thread, I'm under the impression that
> indeed you need to use volatile for unprotected variables accessed across
> threads? For, example, in Ada:
>
> declare
> Global_Exit : Boolean := False;
> -- pragma Volatile (Global_Exit);
> -- pragma Atomic (Global_Exit);
> begin
> -- Lots o'tasks here that monitor Global_Exit for termination.
> end;
>
> Here you don't need a protected, since once someone makes Global_Exit true, the
> end arrives and all is well. I would normally mark that as Atomic which, as it
> implies volatile, is OK.
>
> But let's say one knows that boolean is atomic for the architecture, and makes
> the (risky) decision of not explicitly saying so to the compiler. I understand
> that, without volatile, tasks never writing to Global_Exit could optimize away
> any check for changes on it, and see it as a constant? (Indeed I guess Gnat
> would issue a warning about Global_Exit being constant).
>
> Although in Ada I don't see much (or any?) use for volatile, non-atomic shared
> variables outside of protected objects.
>
> Some flaw in my understanding?
You are correct you should use volatiles. I don't think there is any
need to have volatile inside the protected objects. Access will be
properly serialized anyway.
G.
-
Re: Robert Dewar's great article about the Strengths of Ada over other langauges in multiprocessing!
Sam> You cannot resolve "delete" statically
Maciej> Of course I can. Note that the above is equivalent to:
You stripped the end of my paragraph which contained exactly what you
wrote in response, so this is hardly a rebuttal of what I said. Let me
quote myself:
Sam> unless you add a new "if" in it, which is then equivalent to
Sam> looking up the destructor in the virtual table
Which is exactly what you did (add a new "if").
Sam
--
Samuel Tardieu -- sam@rfc1149.net -- http://www.rfc1149.net/
-
Re: Robert Dewar's great article about the Strengths of Ada overother langauges in multiprocessing!
On 13 Mar, 12:42, gp...@axonx.com wrote:
> OK, your point well taken, so it is up to compiler vendors to
> guarantee volatility under MT.
Vendors can (and should) provide you with some way to write correct MT
programs. This is an issue of normal competition on the market.
There are different ways to do it and language extension is one
possibility. If Microsoft claims that volatile works on their
compiler, it is language extension.
On the GNU side of the world the set of tools does not involve
volatile at all. Instead you get a set of POSIX interfaces that give
necessary guarantees related to memory consistency and visibility
(actually, POSIX gives them for C only, but this isn't a problem
except for standard lawyers).
Windows, as an operating system, provides similar guarantees with
similar interfaces (for example, pthread_mutex_lock in POSIX can be
compared to EnterCriticalSection on Windows). If you have a library
that abstracts the interface differences away (like Boost.Thread), you
can write portable software without any use of volatile. You don't
need volatile, because the system interfaces already provide the
necessary memory consistency and visibility guarantees. And since it
is possible to write portable software this way, it is what I would
recommend.
If you start using volatile relying on language extensions provided by
one particular vendor, you will not be able to easily port this
software to other platforms.
> Does it mean that original purpose of
> volatile ma not always hold either?
Original purpose of volatile did not relate to threads, so nothing
changes there.
To be exact (and to complete the discussion), the volatile type
specifier can be used to implement I/O, for information exchange with
signal handlers and for long jump. None of it is related to threads.
--
Maciej Sobczak * www.msobczak.com * www.inspirel.com
-
Re: Robert Dewar's great article about the Strengths of Ada overother langauges in multiprocessing!
On Mar 13, 12:10 pm, Maciej Sobczak <see.my.homep...@gmail.com> wrote:
> On 13 Mar, 12:42, gp...@axonx.com wrote:
>
> > OK, your point well taken, so it is up to compiler vendors to
> > guarantee volatility under MT.
>
> Vendors can (and should) provide you with some way to write correct MT
> programs. This is an issue of normal competition on the market.
> There are different ways to do it and language extension is one
> possibility. If Microsoft claims that volatile works on their
> compiler, it is language extension.
>
> On the GNU side of the world the set of tools does not involve
> volatile at all. Instead you get a set of POSIX interfaces that give
> necessary guarantees related to memory consistency and visibility
> (actually, POSIX gives them for C only, but this isn't a problem
> except for standard lawyers).
> Windows, as an operating system, provides similar guarantees with
> similar interfaces (for example, pthread_mutex_lock in POSIX can be
> compared to EnterCriticalSection on Windows). If you have a library
> that abstracts the interface differences away (like Boost.Thread), you
> can write portable software without any use of volatile. You don't
> need volatile, because the system interfaces already provide the
> necessary memory consistency and visibility guarantees. And since it
> is possible to write portable software this way, it is what I would
> recommend.
>
> If you start using volatile relying on language extensions provided by
> one particular vendor, you will not be able to easily port this
> software to other platforms.
>
> > Does it mean that original purpose of
> > volatile ma not always hold either?
>
> Original purpose of volatile did not relate to threads, so nothing
> changes there.
> To be exact (and to complete the discussion), the volatile type
> specifier can be used to implement I/O, for information exchange with
> signal handlers and for long jump. None of it is related to threads.
>
> --
> Maciej Sobczak *www.msobczak.com*www.inspirel.com
So if you write to IO through volatile and later read from it, you may
get the same value fetched back by "smart" CPU.
G.
-
Re: Robert Dewar's great article about the Strengths of Ada over other langauges in multiprocessing!
gpriv@axonx.com writes:
> So if you write to IO through volatile and later read from it, you
> may get the same value fetched back by "smart" CPU.
On the PowerPC/VME hardware I'm using, the memory mapping is arranged
so that VME (== IO) space isn't cached. I would imagine the same would
have to be true of any memory-mapped IO scheme.
-
Re: Robert Dewar's great article about the Strengths of Ada overother langauges in multiprocessing!
On 13 Mar, 17:16, gp...@axonx.com wrote:
> So if you write to IO through volatile and later read from it, you may
> get the same value fetched back by "smart" CPU.
I would expect that I/O is realized within the range of memory
addresses that is excluded from the "smart" handling (your BIOS setup
can even allow setting this - I remember seeing it somewhere). In any
case, it is the implementation in its entirety that has to handle it -
somehow. We don't need to bother how it's done.
The full meaning of volatile is defined in terms of its relation to so
called sequence points and program side-effects. There is some place
left just for "magic".
The problem is that when you make something volatile in your program,
it has no special meaning to CPU and is therefore subject to "smart"
optimization.
I have seen once a very interesting model for memory in multi-core and
multi-cpu machines. Imagine that each thread (or tasks in Ada) has its
own private memory. There is also one "global" memory area. There is
some "magic" that makes random bits of private memory propagate at
random times to the global part and another that makes random bits of
global memory propagate at random times to private parts of each
thread (task). This model can sound completely crazy, but actually
foresees all bad things that can happen in MT program - including
reordering.
There are some system-level mechanisms that help control all this mess
and that force the memory blocks to synchronize - these include
mutexes, condvars and membars with release-acquire consistency (in
Ada, you get them with protected objects, entry barriers, etc.).
You should write your program with this crazy model in mind. If you
can make it correct, it will work everywhere.
--
Maciej Sobczak * www.msobczak.com * www.inspirel.com
-
Re: Robert Dewar's great article about the Strengths of Ada over other langauges in multiprocessing!
"Alex R. Mosteo" <devnull@mailinator.com> wrote in message
news:63sn1tF29a5oiU1@mid.individual.net...
....
> Although in Ada I don't see much (or any?) use for volatile, non-atomic
shared
> variables outside of protected objects.
>
> Some flaw in my understanding?
Yes, sort of. You're not considering non-tasking uses. The canonical example
for Volatile is reading/writing a memory-mapped hardware device. In that
case, optimizing out the reads/writes can be fatal. It doesn't directly have
anything to do with tasking. (I suppose one could consider the hardware
device as a sort of task, but it would be done with unusual properties.)
Another purpose is for debugging. You can monitor the memory location of a
Volatile object to see what is going on, without the pragma the compiler can
optimize the entire object away leaving nothing to monitor. (Of course, the
pragma also changes the code, which might change the bug you are trying to
find.)
Also, you can use Volatile on any object, whereas Atomic only works on ones
the compiler can do indivisibly (usually no larger than the word size of the
machine).
OTOH, for communication between tasks, you have to use Atomic. (Thus large
objects need a protected object or other scheme for synchronizing access.)
Randy.