  
  [1X5 [33X[0;0YAtomic objects[133X[101X
  
  [33X[0;0YHPC-GAP  provides  a number of atomic object types. These can be accessed by
  multiple  threads  concurrently  without requiring explicit synchronization,
  but can have non-deterministic behavior for complex operations. Atomic lists
  are  fixed-size  lists;  they  can  be assigned to and read from like normal
  plain  lists.  Atomic  records  are atomic versions of plain records. Unlike
  plain  records, though, it is not possible to delete elements from an atomic
  record. The primary use of atomic lists and records is to facilitate storing
  the  result  of  idempotent  operations  and  to  support  certain low-level
  operations.  Atomic  lists  and records can have three different replacement
  policies:  write-once,  strict  write-once,  and rewritable. The replacement
  policy  determines  whether  an already assigned element can be changed. The
  write-once  policy allows elements to be assigned only once, with subsequent
  assignments being ignored; the strict write-once policy allows elements also
  to  be  assigned  only once, but subsequent assignments will raise an error;
  the  rewritable  policy  allows  elements  to  be  assigned different values
  repeatedly.  The  default  for  new  atomic  objects  is  to  be rewritable.
  Thread-local  records are variants of plain records that are replicated on a
  per-thread basis.[133X
  
  
  [1X5.1 [33X[0;0YAtomic lists[133X[101X
  
  [33X[0;0YAtomic  lists are created using the [10XAtomicList[110X or [10XFixedAtomicList[110X functions.
  After  creation,  they  can be used exactly like any other list, except that
  atomic  lists created with [10XFixedAtomicList[110X cannot be resized. Their contents
  can also be read as normal plain lists using [10XFromAtomicList[110X.[133X
  
  [4X[32X  Example  [32X[104X
    [4X[25Xgap>[125X [27Xa := AtomicList([1,2,4]);[127X[104X
    [4X[28X<atomic list of size 3>[128X[104X
    [4X[25Xgap>[125X [27XWaitTask(RunTask(function() a[1] := a[1] + a[2]; end));[127X[104X
    [4X[25Xgap>[125X [27Xa[1];[127X[104X
    [4X[28X3[128X[104X
    [4X[25Xgap>[125X [27XFromAtomicList(a);[127X[104X
    [4X[28X[ 3, 2, 4 ][128X[104X
  [4X[32X[104X
  
  [33X[0;0YBecause  multiple  threads  can read and write the list concurrently without
  synchronization, the results of modifying the list may be non-deterministic.
  It is faster to write to fixed atomic lists than to a resizable atomic list.[133X
  
  [1X5.1-1 AtomicList[101X
  
  [33X[1;0Y[29X[2XAtomicList[102X( [3Xlist[103X ) [32X function[133X
  [33X[1;0Y[29X[2XAtomicList[102X( [3Xcount[103X, [3Xobj[103X ) [32X function[133X
  
  [33X[0;0Y[2XAtomicList[102X is used to create a new atomic list. It takes either a plain list
  as  an  argument, in which case it will create a new atomic list of the same
  size,  populated  by  the  same  elements; or it takes a count and an object
  argument.  In that case, it creates an atomic list with [3Xcount[103X elements, each
  set to the value of [3Xobj[103X.[133X
  
  [4X[32X  Example  [32X[104X
    [4X[25Xgap>[125X [27Xal := AtomicList([3, 1, 4]);[127X[104X
    [4X[28X<atomic list of size 3>[128X[104X
    [4X[25Xgap>[125X [27Xal[3];[127X[104X
    [4X[28X4[128X[104X
    [4X[25Xgap>[125X [27Xal := AtomicList(10, `"alpha");[127X[104X
    [4X[28X<atomic list of size 10>[128X[104X
    [4X[25Xgap>[125X [27Xal[3];[127X[104X
    [4X[28X"alpha"[128X[104X
    [4X[25Xgap>[125X [27XWaitTask(RunTask(function() al[3] := `"beta"; end));[127X[104X
    [4X[25Xgap>[125X [27Xal[3];[127X[104X
    [4X[28X"beta"[128X[104X
  [4X[32X[104X
  
  [1X5.1-2 FixedAtomicList[101X
  
  [33X[1;0Y[29X[2XFixedAtomicList[102X( [3Xlist[103X ) [32X function[133X
  [33X[1;0Y[29X[2XFixedAtomicList[102X( [3Xcount[103X, [3Xobj[103X ) [32X function[133X
  
  [33X[0;0Y[2XFixedAtomicList[102X works like [2XAtomicList[102X ([14X5.1-1[114X) except that the resulting list
  cannot be resized.[133X
  
  [1X5.1-3 MakeFixedAtomicList[101X
  
  [33X[1;0Y[29X[2XMakeFixedAtomicList[102X( [3Xlist[103X ) [32X function[133X
  
  [33X[0;0Y[2XMakeFixedAtomicList[102X turns a resizable atomic list into a fixed atomic list.[133X
  
  [4X[32X  Example  [32X[104X
    [4X[25Xgap>[125X [27Xa := AtomicList([99]);[127X[104X
    [4X[28X<atomic list of size 1>[128X[104X
    [4X[25Xgap>[125X [27Xa[2] := 100;[127X[104X
    [4X[28X100[128X[104X
    [4X[25Xgap>[125X [27XMakeFixedAtomicList(a);[127X[104X
    [4X[28X<fixed atomic list of size 2>[128X[104X
    [4X[25Xgap>[125X [27Xa[3] := 101;[127X[104X
    [4X[28XError, Atomic List Element: <pos>=3 is an invalid index for <list>[128X[104X
  [4X[32X[104X
  
  [1X5.1-4 FromAtomicList[101X
  
  [33X[1;0Y[29X[2XFromAtomicList[102X( [3Xatomic_list[103X ) [32X function[133X
  
  [33X[0;0Y[2XFromAtomicList[102X  returns  a  plain  list  containing  the  same  elements  as
  [3Xatomic_list[103X  at  the  time  of  the  call.  Because  other threads can write
  concurrently to that list, the result is not guaranteed to be deterministic.[133X
  
  [4X[32X  Example  [32X[104X
    [4X[25Xgap>[125X [27Xal := AtomicList([10, 20, 30]);;[127X[104X
    [4X[25Xgap>[125X [27XWaitTask(RunTask(function() al[2] := 40; end));[127X[104X
    [4X[25Xgap>[125X [27XFromAtomicList(al);[127X[104X
    [4X[28X[ 10, 40, 30 ][128X[104X
  [4X[32X[104X
  
  [1X5.1-5 ATOMIC_ADDITION[101X
  
  [33X[1;0Y[29X[2XATOMIC_ADDITION[102X( [3Xatomic_list[103X, [3Xindex[103X, [3Xvalue[103X ) [32X function[133X
  
  [33X[0;0Y[2XATOMIC_ADDITION[102X  is  a  low-level  operation  that  atomically adds [3Xvalue[103X to
  [3Xatomic_list[index][103X.  It  returns  the  value of [3Xatomic_list[index][103X after the
  addition has been performed.[133X
  
  [4X[32X  Example  [32X[104X
    [4X[25Xgap>[125X [27Xal := FixedAtomicList([4,5,6]);;[127X[104X
    [4X[25Xgap>[125X [27XATOMIC_ADDITION(al, 2, 7);[127X[104X
    [4X[28X12[128X[104X
    [4X[25Xgap>[125X [27XFromAtomicList(al);[127X[104X
    [4X[28X[ 4, 12, 6 ][128X[104X
  [4X[32X[104X
  
  [1X5.1-6 COMPARE_AND_SWAP[101X
  
  [33X[1;0Y[29X[2XCOMPARE_AND_SWAP[102X( [3Xatomic_list[103X, [3Xindex[103X, [3Xold[103X, [3Xnew[103X ) [32X function[133X
  
  [33X[0;0Y[2XCOMPARE_AND_SWAP[102X   is   an   atomic   operation.   It   atomically  compares
  [3Xatomic_list[index][103X to [3Xold[103X and, if they are identical, replaces the value (in
  the  same  atomic  step)  with  [3Xnew[103X. It returns true if the replacement took
  place, false otherwise.[133X
  
  [33X[0;0YThe  primary  use  of  [2XCOMPARE_AND_SWAP[102X  is to implement certain concurrency
  primitives; most programmers will not need to use it.[133X
  
  
  [1X5.2 [33X[0;0YAtomic records and component objects[133X[101X
  
  [33X[0;0YAtomic  records  are  atomic  counterparts  to  plain  records. They support
  assignment  to  individual  record  fields, and conversion to and from plain
  records.[133X
  
  [33X[0;0YAssignment  semantics can be specified on a per-record basis if the assigned
  record field is already populated, allowing either an overwrite, keeping the
  existing value, or raising an error.[133X
  
  [33X[0;0YIt is not possible to unbind atomic record elements.[133X
  
  [33X[0;0YLike  plain  records,  atomic  records can be converted to component objects
  using [10XObjectify[110X.[133X
  
  [1X5.2-1 AtomicRecord[101X
  
  [33X[1;0Y[29X[2XAtomicRecord[102X( [3Xcapacity[103X ) [32X function[133X
  [33X[1;0Y[29X[2XAtomicRecord[102X( [3Xrecord[103X ) [32X function[133X
  
  [33X[0;0Y[2XAtomicRecord[102X  is  used  to  create  a new atomic record. Its single optional
  argument is either a positive integer, denoting the intended capacity (i.e.,
  number  of  elements  to  be  held) of the record, in which case a new empty
  atomic record with that initial capacity will be created. Alternatively, the
  caller  can  provide  a  plain  record  with which to initially populate the
  atomic record.[133X
  
  [4X[32X  Example  [32X[104X
    [4X[25Xgap>[125X [27Xr := AtomicRecord(rec( x := 2 ));[127X[104X
    [4X[28X<atomic record 1/2 full>[128X[104X
    [4X[25Xgap>[125X [27Xr.y := 3;[127X[104X
    [4X[28X3[128X[104X
    [4X[25Xgap>[125X [27XTaskResult(RunTask(function() return r.x + r.y; end));[127X[104X
    [4X[28X5[128X[104X
    [4X[25Xgap>[125X [27X[ r.x, r.y ];[127X[104X
    [4X[28X[ 2, 3 ][128X[104X
  [4X[32X[104X
  
  [33X[0;0YAny  atomic  record  can later grow beyond its initial capacity. There is no
  limit to the number of elements it can hold other than available memory.[133X
  
  [1X5.2-2 FromAtomicRecord[101X
  
  [33X[1;0Y[29X[2XFromAtomicRecord[102X( [3Xrecord[103X ) [32X function[133X
  
  [33X[0;0Y[2XFromAtomicRecord[102X  returns  a  plain record copy of the atomic record [3Xrecord[103X.
  This copy is shallow; elements of [3Xrecord[103X will not also be copied.[133X
  
  [4X[32X  Example  [32X[104X
    [4X[25Xgap>[125X [27Xr := AtomicRecord();;[127X[104X
    [4X[25Xgap>[125X [27Xr.x := 1;; r.y := 2;; r.z := 3;;[127X[104X
    [4X[25Xgap>[125X [27XFromAtomicRecord(r);[127X[104X
    [4X[28Xrec( x := 1, y := 2, z := 3 )[128X[104X
  [4X[32X[104X
  
  
  [1X5.3 [33X[0;0YReplacement policy functions[133X[101X
  
  [33X[0;0YThere  are  three  functions  that  set  the replacement policy of an atomic
  object.  All  three  can also be used with plain lists and records, in which
  case  an  atomic version of the list or record is first created. This allows
  programmers  to elide [2XAtomicList[102X ([14X5.1-1[114X) and [2XAtomicRecord[102X ([14X5.2-1[114X) calls when
  the next step is to change their policy.[133X
  
  [1X5.3-1 MakeWriteOnceAtomic[101X
  
  [33X[1;0Y[29X[2XMakeWriteOnceAtomic[102X( [3Xobj[103X ) [32X function[133X
  
  [33X[0;0Y[2XMakeWriteOnceAtomic[102X takes a list, record, atomic list, atomic record, atomic
  positional  object,  or  atomic  component  object  as  its argument. If the
  argument  is a non-atomic list or record, then the function first creates an
  atomic  copy  of  the  argument.  The  function then changes the replacement
  policy  of  the object to write-once: if an element of the object is already
  bound, then further attempts to assign to it will be ignored.[133X
  
  [1X5.3-2 MakeStrictWriteOnceAtomic[101X
  
  [33X[1;0Y[29X[2XMakeStrictWriteOnceAtomic[102X( [3Xobj[103X ) [32X function[133X
  
  [33X[0;0Y[2XMakeStrictWriteOnceAtomic[102X  works  like  [2XMakeWriteOnceAtomic[102X  ([14X5.3-1[114X), except
  that  the replacement policy is being changed to being strict write-once: if
  an  element  is  already  bound,  then further attempts to assign to it will
  raise an error.[133X
  
  [1X5.3-3 MakeReadWriteAtomic[101X
  
  [33X[1;0Y[29X[2XMakeReadWriteAtomic[102X( [3Xobj[103X ) [32X function[133X
  
  [33X[0;0Y[2XMakeReadWriteAtomic[102X  is  the  inverse  of  [2XMakeWriteOnceAtomic[102X  ([14X5.3-1[114X)  and
  [2XMakeStrictWriteOnceAtomic[102X  ([14X5.3-2[114X)  in  that the replacement policy is being
  changed  to  being  rewritable:  Elements  can  be replaced even if they are
  already bound.[133X
  
  
  [1X5.4 [33X[0;0YThread-local records[133X[101X
  
  [33X[0;0YThread-local  records  allow an easy way to have a separate copy of a record
  for each indvidual thread that is accessed by the same name in each thread.[133X
  
  [4X[32X  Example  [32X[104X
    [4X[25Xgap>[125X [27Xr := ThreadLocalRecord();; # create new thread-local record[127X[104X
    [4X[25Xgap>[125X [27Xr.x := 99;;[127X[104X
    [4X[25Xgap>[125X [27XWaitThread( CreateThread( function()[127X[104X
    [4X[25X>[125X [27X                             r.x := 100;[127X[104X
    [4X[25X>[125X [27X                             Display(r.x);[127X[104X
    [4X[25X>[125X [27X                             end ) );[127X[104X
    [4X[28X100[128X[104X
    [4X[25Xgap>[125X [27Xr.x;[127X[104X
    [4X[28X99[128X[104X
  [4X[32X[104X
  
  [33X[0;0YAs  can  be seen above, even though [10Xr.x[110X is overwritten in the second thread,
  it does not affect the value of [10Xr.x| in the first thread[110X[133X
  
  [1X5.4-1 ThreadLocalRecord[101X
  
  [33X[1;0Y[29X[2XThreadLocalRecord[102X( [[3Xdefaults[103X[, [3Xconstructors[103X]] ) [32X function[133X
  
  [33X[0;0Y[2XThreadLocalRecord[102X  creates  a  new thread-local record. It accepts up to two
  initial  arguments. The [3Xdefaults[103X argument is a record of default values with
  which each thread-local copy is initially populated (this happens on demand,
  so  values  are  not  actually  read until needed). The second argument is a
  record of constructors; parameterless functions that return an initial value
  for  the respective element. Constructors are evaluated only once per thread
  and  only  if  the  respective element is accessed without having previously
  been assigned a value.[133X
  
  [4X[32X  Example  [32X[104X
    [4X[25Xgap>[125X [27Xr := ThreadLocalRecord( rec(x := 99),[127X[104X
    [4X[25X>[125X [27X     rec(y := function() return 101; end));;[127X[104X
    [4X[25Xgap>[125X [27Xr.x;[127X[104X
    [4X[28X99[128X[104X
    [4X[25Xgap>[125X [27Xr.y;[127X[104X
    [4X[28X101[128X[104X
    [4X[25Xgap>[125X [27XTaskResult(RunTask(function() return r.x; end));[127X[104X
    [4X[28X99[128X[104X
    [4X[25Xgap>[125X [27XTaskResult(RunTask(function() return r.y; end));[127X[104X
    [4X[28X101[128X[104X
  [4X[32X[104X
  
  [1X5.4-2 SetTLDefault[101X
  
  [33X[1;0Y[29X[2XSetTLDefault[102X( [3Xrecord[103X, [3Xname[103X, [3Xvalue[103X ) [32X function[133X
  
  [33X[0;0Y[2XSetTLDefault[102X  can  be  used to set the default value of a record field after
  its  creation.  Here, [3Xrecord[103X is a thread-local record, [3Xname[103X is the string of
  the field name, and [3Xvalue[103X is the value.[133X
  
  [4X[32X  Example  [32X[104X
    [4X[25Xgap>[125X [27Xr := ThreadLocalRecord();;[127X[104X
    [4X[25Xgap>[125X [27XSetTLDefault(r, "x", 314);[127X[104X
    [4X[25Xgap>[125X [27Xr.x;[127X[104X
    [4X[28X314[128X[104X
    [4X[25Xgap>[125X [27XTaskResult(RunTask(function() return r.x; end));[127X[104X
    [4X[28X314[128X[104X
  [4X[32X[104X
  
  [1X5.4-3 SetTLConstructor[101X
  
  [33X[1;0Y[29X[2XSetTLConstructor[102X( [3Xrecord[103X, [3Xname[103X, [3Xfunc[103X ) [32X function[133X
  
  [33X[0;0Y[2XSetTLConstructor[102X can be used to set the constructor of a thread-local record
  field after its creation, similar to [2XSetTLDefault[102X ([14X5.4-2[114X).[133X
  
  [4X[32X  Example  [32X[104X
    [4X[25Xgap>[125X [27Xr := ThreadLocalRecord();;[127X[104X
    [4X[25Xgap>[125X [27XSetTLConstructor(r, "x", function() return 2718; end);[127X[104X
    [4X[25Xgap>[125X [27Xr.x;[127X[104X
    [4X[28X2718[128X[104X
    [4X[25Xgap>[125X [27XTaskResult(RunTask(function() return r.x; end));[127X[104X
    [4X[28X2718[128X[104X
  [4X[32X[104X
  
