Creating your own InterlockedXxx operation

Sometimes your design requires an Interlocked operation that is not currently supported by the OS, runtime libraries, or the compiler (as an intrinsic). You then have a choice to make. Either remove all Interlocked operations for that particular field and use a lock or roll you own Interlocked function. Roll your own Interlocked function? Sounded scary to me the first time it was suggested, but in reality it is a rather easy thing to do. Here is the basic algorithm (which I did not invent, it is a well tested and known algorithm)  and a couple of concrete examples

     LONG
    InterlockedYyy(
        __inout LONG  volatile *Target,
        [Additional parameters as needed for operation Yyy]
        )
    {
        LONG prevValue, prevCopy;
    
        prevValue = *Target;
    
        do {
            [Optional comparison]
    
            prevCopy = prevValue;
    
            //
            // prevValue will be the value that used to be Target if the exchange was made
            // or its current value if the exchange was not made.
            //
            prevValue = InterlockedCompareExchange(Target, Yyy operation on prevCopy, prevValue);
    
            //
            // If prevCopy == prevValue, then no one updated Target in between the deref at the top
            // and the InterlockecCompareExchange afterward and we are done
            //
        } while (prevCopy != prevValue);
    
        //
        // [value] can be anything you want, but it is typically either
        // a) The new value stored in Target.  This is the type of return value that 
        //    InterlockedIncrement returns
        // or
        // b) The new value is the previous value that was in Target.  This si the 
        //     type of return value that InterlockedOr or InterlockedExchange return
        //
        return [value];
    }

From this algorithm you can implement nearly anything you want. For instance, let's say that you want to increment Target if and only if it's current value is greater then zero. This allows you to never go from zero to one, a common problem when you implement a reference count. Since this Interlocked operation can "fail," we need a way to convey failure.  In this case I chose to return the Floor value since it is an not a value that could ever be returned in the success path.  Algorithm specific modifications to the generic algorithm are in red

     LONG
    MyInterlockedIncrementWithFloor(
        __inout LONG  volatile *Target,
        LONG Floor
        )
    {
        LONG prevValue, prevCopy;
    
        prevValue = *Target;
    
        do {
            if (prevValue <= Floor) {
                return Floor;
            }
    
            prevCopy = prevValue;
    
            //
            // prevValue will be the value that used to be Target if the exchange was made
            // or its current value if the exchange was not made.
            //
            prevValue = InterlockedCompareExchange(Target, prevCopy+1, prevValue);
    
            //
            // If prevCopy == prevValue, then no one updated Target in between the deref at the top
            // and the InterlockecCompareExchange afterward and we are done
            //
        } while (prevCopy != prevValue);
    
        //
        // prevCopy is the old value of Target. Since InterlockedIncrement returns the new
        // incremented value of Target, we should do the same here.
        //
        return prevCopy+1;
    }

Let's say you wanted to XOR in a value in the high word of the Target and clear the low word, you could implement it this way

     LONG
    MyInterlockedXorHighClearLowWord(
        __inout LONG  volatile *Target,
        SHORT HighWord
        )
    {
        LONG prevValue, prevCopy;
    
        prevValue = *Target;
    
        do {
            // No conditional check like the previous example
             prevCopy = prevValue;
    
            //
            // prevValue will be the value that used to be Target if the exchange was made
            // or its current value if the exchange was not made.
            //
            prevValue = InterlockedCompareExchange(
                Target, 
                (prevCopy ^ (HighWord << 16) & (~0xFFFF),
                prevValue);
    
            //
            // If prevCopy == prevValue, then no one updated Target in between the deref at the top
            // and the InterlockecCompareExchange afterward and we are done
            //
        } while (prevCopy != prevValue);
    
        //
        // prevCopy is the old value of Target. Returns the old value of Target
        // (just to demonstrate the 2nd pattern for which return type you can use)     
        //
        return prevCopy;
    }