logo
Free, unlimited AI code reviews that run on commit
git-lrc git-lrc GitHub Install Now We'd appreciate a star git-lrc - Free, unlimited AI code reviews that run on commit | Product Hunt git-lrc - Free, unlimited AI code reviews that run on commit | Product Hunt

Atomic - Atomic references.

Documentation

       Module Atomic
        : sigend

       Atomic references.

       See Atomic.examples below.  See 'Memory model: The hard bits' chapter in the manual.

       Since 4.12

       type!'at

       An atomic (mutable) reference to a value of type 'a .

       valmake : 'a->'at

       Create an atomic reference.

       valmake_contended : 'a->'at

       Create  an  atomic reference that is alone on a cache line. It occupies 4-16x the memory of one allocated
       with makev .

       The primary purpose is to prevent false-sharing and the resulting performance  degradation.  When  a  CPU
       performs  an  atomic  operation, it temporarily takes ownership of an entire cache line that contains the
       atomic reference. If multiple atomic references share the  same  cache  line,  modifying  these  disjoint
       memory  regions  simultaneously  becomes  impossible,  which can create a bottleneck. Hence, as a general
       guideline, if an atomic reference is experiencing contention, assigning it its own cache line may enhance
       performance.

       valget : 'at->'a

       Get the current value of the atomic reference.

       valset : 'at->'a->unit

       Set a new value for the atomic reference.

       valexchange : 'at->'a->'a

       Set a new value for the atomic reference, and return the current value.

       valcompare_and_set : 'at->'a->'a->boolcompare_and_setrseenv sets the new value of r to v only if its current value is  physically  equal  to
       seen -- the comparison and the set occur atomically. Returns true if the comparison succeeded (so the set
       happened) and false otherwise.

       valfetch_and_add : intt->int->intfetch_and_addrn atomically increments the value of r by n , and returns the current value (before the
       increment).

       valincr : intt->unitincrr atomically increments the value of r by 1 .

       valdecr : intt->unitdecrr atomically decrements the value of r by 1 .

   ExamplesBasicThreadCoordination
       A basic use case is to have global counters that are updated in a thread-safe way, for  example  to  keep
       some  sorts  of  metrics  over  IOs performed by the program. Another basic use case is to coordinate the
       termination of threads in a given program, for example when one thread  finds  an  answer,  or  when  the
       program is shut down by the user.

       Here, for example, we're going to try to find a number whose hash satisfies a basic property. To do that,
       we'll run multiple threads which will try random numbers until they find one that works.

       Of course the output below is a sample run and will change every time the program is run.

           (*usefortermination*)letstop_all_threads=Atomic.makefalse(*totalnumberofindividualattemptstofindanumber*)letnum_attempts=Atomic.make0(*findanumberthatsatisfies[p],by...tryingrandomnumbersuntilonefits.*)letfind_number_where(p:int->bool)=letrand=Random.State.make_self_init()inwhilenot(Atomic.getstop_all_threads)doletn=Random.State.full_intrandmax_intinignore(Atomic.fetch_and_addnum_attempts1:int);ifp(Hashtbl.hashn)then(Printf.printf"found%d(hash=%d)\n%!"n(Hashtbl.hashn);Atomic.setstop_all_threadstrue;(*signalallthreadstostop*))done;;(*runmultipledomainstosearchfora[n]where[hashn<=100]*)let()=letcriterionn=n<=100inletthreads=Array.init8(fun_->Domain.spawn(fun()->find_number_wherecriterion))inArray.iterDomain.jointhreads;Printf.printf"totalnumberofattempts:%d\n%!"(Atomic.getnum_attempts);;-:unit=()found1651745641680046833(hash=33)totalnumberofattempts:30230350TreiberStack
       Another example is a basic Treiber stack (a thread-safe stack) that can be safely shared between threads.

       Note  how  both push and pop are recursive, because they attempt to swap the new stack (with one more, or
       one fewer, element) with the old stack.  This is optimistic concurrency: each  iteration  of,  say,  pushstackx  gets the old stack l , and hopes that by the time it tries to replace l with x::l , nobody else
       has had time to modify the list. If the compare_and_set fails it means we were too optimistic,  and  must
       try again.

           type'astack='alistAtomic.tletrecpush(stack:_stack)elt:unit=letcur=Atomic.getstackinletsuccess=Atomic.compare_and_setstackcur(elt::cur)inifnotsuccessthenpushstackeltletrecpop(stack:_stack):_option=letcur=Atomic.getstackinmatchcurwith|[]->None|x::tail->letsuccess=Atomic.compare_and_setstackcurtailinifsuccessthenSomexelsepopstack#letst=Atomic.make[]#pushst1-:unit=()#pushst2-:unit=()#popst-:intoption=Some2#popst-:intoption=Some1#popst-:intoption=None

OCamldoc                                           2025-06-12                                         Atomic(3o)

Module

       Module   Atomic

Name

       Atomic - Atomic references.

See Also