(j3.2006) Lock variables

Andy Vaught andyv
Tue Mar 10 13:17:58 EDT 2009


On Tue, 10 Mar 2009, Bill Long wrote:

> Van Snyder wrote:
> > On Mon, 2009-03-09 at 17:41 -0700, Malcolm Cohen wrote:
> >   
> >> Van Snyder wrote:
> >>     
> >>> For now,
> >>> it would just be a silly program that locks a noncoarray lock -- until
> >>> we implement task parallelism, at which time it will make sense.
> >>>   
> >>>       
> >> It seems highly likely to me that the data structure and locking 
> >> mechanism needed for a task lock and that needed by a coarray lock would 
> >> very likely be significantly different, probably to the extent that 
> >> providing a single lock type that does both jobs would perform 
> >> significantly worse than either kind.  The same applies to critical 
> >> sections.
> >>
> >> Certainly if by task parallelism you mean running in the same address 
> >> space (i.e. within a single image) I wouldn't build task locks on top of 
> >> coarray locks, or indeed much of the task parallel infrastructure on any 
> >> of the coarray parallel infrastructure.  Maybe that's just me though.
> >>     
> >
> > This is precisely why I advocated in 08-202 to spell LOCK as COLOCK and
> > UNLOCK as COUNLOCK and LOCK_TYPE as COLOCK_TYPE and CRITICAL as
> > COCRITICAL, so that when (if ever) we want the same beasts for task
> > parallelism but with different underlying mechanisms, we don't need to
> > spell them NONCOLOCK, NONCOUNLOCK, NONCOLOCK_TYPE and NONCOCRITICAL.  A
> > straw vote (1-6-2) decided this wasn't necessary.  See 08-274.
> >   
> 
> I agree the Malcolm that the implementation characteristics of locks for 
> images and local threads would most likely be different.  I don't think 
> anyone would go for names like NONCOLOCK (assuming we ever go this 
> route). More reasonable options, like TLOCK (thread lock), would 
> probably be proposed.


  My understanding is that this was rejected because it was judged too
complicated, but giving portable access to compare-and-swap allows
construction of any number of locks like test-and-set, test-and-clear,
atomic increment/decrement and also allows building more complicated
lock-free algorithms.

  A compare and swap works for single threads, multiple threads, coarrays
implemented as shared memory and coarrays implemented as messages over
networks.

  Instead of a two new statments, a new intrinsic derived type and half a
dozen new intrinsic procedures, all that is needed is a single intrinsic
procedure:

-----------------------------------------------------
COMPARE_AND_SWAP(VAR, OLD, NEW, SUCCESS)

Description:  Atomically compares the value of VAR with OLD and sets VAR
to NEW if it was equal to OLD.  Otherwise leaves VAR alone.  The SUCCESS
variable is set to .TRUE. if the new value was stored, .FALSE. otherwise.

Class:  Elemental subroutine

Arguments:

VAR        An INTENT(INOUT) variable of a processor-supported
           type and kind.  Default integer must be supported.
           VAR may be a pointer variable.

OLD        Shall be of same kind and type as VAR.  INTENT(IN)

NEW        Shall be of same kind and type as VAR.  INTENT(IN)

SUCCESS    Shall be of type LOGICAL, INTENT(OUT)
-----------------------------------------------------


Examples:
------------

logical function test_and_set(flag)
logical, volatile, intent(inout) :: flag
logical :: test_and_set

  call compare_and_swap(flag, .FALSE., .TRUE., test_and_set)
end 


logical function test_and_clear(flag)
logical, volatile, intent(inout) :: flag

  call compare_and_swap(flag, .TRUE., .FALSE., test_and_clear)
end


subroutine atomic_increment(count)
integer, volatile, intent(inout) :: count
logical :: success
integer :: value, n

! Fortran still lacks a portable way of delaying, but it's easy enough to
! just call usleep() these days.

interface
  subroutine usleep(time), bind(c)
    integer(kind=c_long) :: time
  end subroutine usleep
end interface

  n = 0
  do
    value = count       ! 'count' is volatile, so read it once here!
    call compare_and_swap(count, value, value+1, success)

    if (success) exit

    n = min(n+1, 10)    ! Exponential backoff on failure
    call usleep(2**n)
  enddo

end subroutine




-- Andy





More information about the J3 mailing list