(j3.2006) (SC22WG5.3701) Atomic stuff

Van Snyder Van.Snyder
Tue Dec 2 21:52:09 EST 2008


I wasn't entirely satisfied with the way we provided for atomic memory
operations in Tokyo, but I wanted to think about it some more before
bringing it up.

I can think of three ways that I would prefer to the intrinsic
subroutines described in 08-297r1.

1.  Provide an attribute for a variable that says accesses to it are
atomic.  This seems to have been the intent of the use of VOLATILE in
08-007r2:Note 8.28.  One might desire to enclose the declaration and
access within a BLOCK, so the attribute would work like ASYNCHRONOUS in
that respect: a declaration of the attribute within a BLOCK isn't a
declaration of a new variable.  So the spin loop in Note 8.38 becomes

        use, intrinsic :: ISO_FORTRAN_ENV, only: Atomic_logical_kind
        logical(atomic_logical_kind) :: LOCKED[*] = .true.
        integer :: P, Q
        BLOCK
          atomic :: LOCKED
          if ( this_image() == p ) then
            sync memory
            locked[q] = .false.
            sync memory
          else
            do while ( locked ); end do
          end if
        end BLOCK

Notice no VAL variable is needed.

2.  Use the function/updater syntax I've been advocating for more than
twenty years.  Suppose an intrinsic function/updater pair are called
ATOMIC.  Assume they have SYNC MEMORY in them as needed.  Then the spin
loop in Note 8.38 becomes

        use, intrinsic :: ISO_FORTRAN_ENV, only: Atomic_logical_kind
        logical(atomic_logical_kind) :: LOCKED[*] = .true.
        integer :: P, Q
        if ( this_image() == p ) then
          atomic(locked[q]) = .false.
        else
          do while ( atomic(locked) ); end do
        end if

3.  Define type-bound function/updater pairs, named, say ATOMIC, as we
did for access to complex parts.  Again, the function and/or updater are
assumed to have SYNC MEMORY in them as needed.  Then the spin loop in
Note 8.38 becomes

        use, intrinsic :: ISO_FORTRAN_ENV, only: Atomic_logical_kind
        logical(atomic_logical_kind) :: LOCKED[*] = .true.
        integer :: P, Q
        if ( this_image() == p ) then
          locked[q]%atomic = .false.
        else
          do while ( locked%atomic ); end do
        end if

I prefer any of these to 08-297r1.

Each of these could be specified to be available only for variables of
specified type and kind, just as for the intrinsic subroutines in
08-297r1.

The last two require careful definition in the case an atomic thing-o is
an actual argument: Are copy semantics used, or is ATOMIC a thunk?
Whether a thunk or copy could depend upon an attribute of the
corresponding dummy argument, say ACTIVE.  Saying so with a dummy
argument attribute would be useful in other contexts as well.

Other cases, such as appearing in an I/O list, are obvious in all three
methods, and impossible with the intrinsic subroutine method.

Actually, I would prefer a much higher level concept, similar to an Ada
protected variable (once again I urge you to consult "Concurrent and
Real-Time Programming in Ada" by Andy Wellings and Alan Burns).  These
let you customize your synchronization strategy just as much as atomic
references do, but it's much less likely you'll botch things.  These
would have to be thunks.

-- 
Van Snyder                    |  What fraction of Americans believe 
Van.Snyder at jpl.nasa.gov       |  Wrestling is real and NASA is fake?
Any alleged opinions are my own and have not been approved or
disapproved by JPL, CalTech, NASA, the President, or anybody else.




More information about the J3 mailing list