Saturday, August 29, 2015

Lock Free Volatile Field Updates


        void LockfreeUpdate(ref double volatileUpdateTarget, double value)
        {
            SpinWait sw = new SpinWait();
            while (true)
            {
                // after this line, other thread can update the ref double,
                double comparandAsSnapshot = volatileUpdateTarget;

                //w/o barrier, before instruction changing volatileUpdateTarget move to after Snapshot=> comparandAsSnapshot stale=>extra spin
                Thread.MemoryBarrier();

                // if preempted=>updateTarget changed != comparand=> no copy, and spin.
                double? originalRefValueBeforeExchComp = Interlocked.CompareExchange(ref volatileUpdateTarget, value, comparandAsSnapshot);
                if (originalRefValueBeforeExchComp == comparandAsSnapshot) return;  // no preemption
                sw.SpinOnce();
            }
        }
 
       void LockfreeUpdate<T>(ref T volatileUpdateTarget,T value) where T: class
        {
            SpinWait sw = new SpinWait();
            while (true)
            {
                // after this line, other thread can update the ref double,
                T comparandAsSnapshot = volatileUpdateTarget;

                 // ICE has internal MemoryBarrier so just extra spin here

                // if preempted=>updateTarget changed != comparand=> no copy, and spin.
                T originalRefValueBeforeExchComp = Interlocked.CompareExchange(ref volatileUpdateTarget, value, comparandAsSnapshot);
                if (originalRefValueBeforeExchComp == comparandAsSnapshot) return;  // no preemption
                sw.SpinOnce();
            }
        }

       void LockfreeUpdate<T>(ref T volatileUpdateTarget,func<T,T> updateFunc) where T: class
        {
            SpinWait sw = new SpinWait();
            while (true)
            {
                // after this line, other thread can update the ref double,
                T comparandAsSnapshot = volatileUpdateTarget;

                // if preempted=>updateTarget changed != comparand=> no copy, and spin.
                T originalRefValueBeforeExchComp = Interlocked.CompareExchange(ref volatileUpdateTarget, 
         updateFunc(comparandAsSnapshot ), comparandAsSnapshot);
                if (originalRefValueBeforeExchComp == comparandAsSnapshot) return;  // no preemption
                sw.SpinOnce();
            }
        }