>>>>> "Robert" == Robert Dewar <[EMAIL PROTECTED]> writes:

 Robert> Paul Koning wrote:
 >>>>>>> "Robert" == Robert Dewar <[EMAIL PROTECTED]> writes:
 >>
 Robert> Ken Raeburn wrote:
 >> >> That's what I thought.  So, unless the compiler (or language
 >> spec) >> is going to become thread-aware, any data to be shared
 >> across >> threads needs to be declared volatile, even if some
 >> other >> mechanism (like a mutex) is in use to do some
 >> synchronization.  >> Which means performance would be poor for any
 >> such data.
 >> 
 Robert> The use of shared variables without synchronization is rare
 Robert> in any case in most code.
 >> You mean "without explicit synchronization" via mutexes or the
 >> like?
 >> 
 >> It seems that the classic circular buffer communication mechanisms
 >> have been forgotten by many, but they still work quite well and
 >> require no mutexes or the like.  All that is required is
 >> sufficiently ordered memory accesses.

 Robert> Sure such alogorithms are interesting on mono processors, ...

They work fine on multi-processors too, of course.  That's where they
first showed up, in CDC 6000 series machines for communication between
CPU and PPU.

 Robert> Nevertheless such usage is relatively rare, and volatile is
 Robert> good enough, I see no basis for any changes to the compiler.

Maybe they are rare because people no longer learn them, even though
they are the most efficient answer in a lot of cases where they end up
using heavier solutions instead.  I remember being amazed that RTLinux
(some years ago) was using interrupt enable/disable to synchronize
control variables in an RTLinux to Linux communication mechanism, when
circular buffers would provide the same service without any need of
interrupt lockout or other explicit synchronization at all.

Also: circular buffers are a VERY common communication mechanism
in DMA devices.  For example, many Ethernet NICs use them.  They may
not be exactly CDC 6000 "CIO" ring buffers, but the basic idea is
similar and the memory access properties needed are analogous.

 >> I'm using circular buffers to communicate between threads.  I drop
 >> data into the buffer and move the "in" pointer; the consumer
 >> compares the pointers, reads data from the buffer, and advances
 >> the "out" pointer.  The current code has the pointers declared as
 >> volatile, buf the buffer data area is not (and I wouldn't want it
 >> to be -- that seems to be a performance issue).

 Robert> Of course the buffer data area must be declared as volatile,
 Robert> otherwise the compiler is free to make and hold private
 Robert> copies of elements in separate threads. It probably won't in
 Robert> practice, but to rely on this is non-portable.

Ok.  I think that may be the issue that people are talking about with
the comments about volatile being a costly solution.

I'm using memcpy() to load/unload buffer data.  Is memcpy defined for
volatile variables?  If yes, and I declare the buffer as a char array
(logical, since the threads can pass arbitrary quantities of bytes),
would the generated code be required by the semantics of "volatile" to
do individual loads and stores for every byte?  That is the problem.
What's needed is (a) no code movement across the pointer operations,
(b) the data copy can be fully optimized, as is typically done with
memcpy, (c) no old data hangs around in registers.

I guess GCC lets us do this with asm ("":::"memory") but of course
that isn't portable either...

         paul

Reply via email to