SPUG: threading, atomicity and safeness

Joshua ben Jore twists at gmail.com
Sat May 3 09:02:32 PDT 2008


On Mon, Apr 28, 2008 at 2:47 PM, Fred Morris <m3047 at inwa.net> wrote:
> "Atomicity" refers to an operation which simply cannot and will not be
>  interrupted. For instance a single machine instruction executing on a single
>  CPU is generally considered atomic (although the VAX had certain machine
>  instructions which *were* interruptible, and had certain others which had an
>  "interlocked" form which asserted a halt against other CPUs on the bus IIRC).
>  So no thread can possibly be interrupted in the middle of one of these
>  operations.
>
>  "Safeness" refers to something which happens up a level or two, when compilers
>  optimize instructions out of memory and into registers... hence it is not
>  safe for multiple threads to attempt to modify the "same" variable (because
>  each has a different register copy)... and therefore compilers end up with
>  "unsafe" pragmas and flags to keep certain variables from being optimized
>  that way.
>
>  This gets a little inside-out or at least the level of abstraction is more or
>  less levelled out, but I find myself wondering some of these same things
>  about Perl (and Python) and I don't find any discussion of these issues.
>
>  Who cares? Well:
>
>  * Atomicity means you can modify a value (on the VAX this was not just store,
>  but increment and add... and a few other oddball things) without throwing a
>  lock around it. Ok, maybe this "just isn't safe" if you've never taken a dive
>  beneath the flotsam generated by compilers and so you just don't go there,
>  but if you've ever written assembler maybe you've skipped a couple
>  locking/semaphore library calls with complete impunity... besides, it's
>  faster (that's a fact).
>
>  * Safeness means that two threads are actually assured that they are in fact
>  reading (or I suppose updating, but if reading isn't safe then who cares) the
>  same value... or at least the same storage location (since they might not
>  read it at the same time, and without locking the value could change).
>
>  Assume I'm talking about a hash because it's been blessed into a class as an
>  instance (and because I'm curious about the same questions regarding Python,
>  and its instances are basically hashes).
>
>  So then, given that I have two threads which are free-running, I pose these
>  questions:
>
>  * Is "$self->{foo} = $x;" atomic: that is, can I assume that if two threads
>  start to update $self->{foo} at the "same" time (or one starts updating while
>  the other starts reading), the one which actually goes first will finish
>  first?

No. The statement $self->{foo} = $x decomposes to the following atomic
operations:

sassign(
  helem(
    rv2hv(
      padsv( '$self' )
    )
    const( 'foo' )
  )
  padsv( '$x' )
)

For synchronization purposes, you must be sure that all your variables
are locked appropriately. In your example, there are four variables
each of which may need to be locked depending on what all you're
sharing.

The scalar $self.
The hash %$self.
The scalar $self->{'foo'}.
The scalar $x.

>  * Is "$self->{foo}++;" atomic? Ok, I had to ask. ;-) If it was, then the next

Also no. Here is the decomposition of your above expression.

preinc(
  helem(
    rv2hv(
      padsv( '$self' )
    )
    const( 'foo' )
  )
)

>  * Is "$x = $self->{foo};" safe?

Yes, provided you use locks. All the above is also safe provided you
use locks. If you would like to get away from this in Perl 5, consider
using DBM::Deep to synchronize your shared state.

Josh


More information about the spug-list mailing list