1

I don't know why, but I can't quite seem to wrap my head around what's going on in Interlocked.CompareExchange(ref int a, int b, int c).

Could someone show me what it would be doing, if it were just naively implemented in a single-threaded environment?

i.e. what code is it replacing with a "do that ... but as an atomic, thread-safe operation"?

Brondahl
  • 7,402
  • 5
  • 45
  • 74
  • 2
    In single-threaded land, that code means (I believe): `if (a == c) { a = b; }`. Since it reads two operands and then does a write as part of the single operation, it is not naturally atomic. The `CompareExchange` call makes it atomic (Intel architecture machines have an atomic instruction to do this - on other machines, it may involve some kind of lock) – Flydog57 Dec 17 '19 at 23:24

2 Answers2

3

Here's my understanding of the code (in single-threaded land):

static int CompareExchange(ref int location1, int value, int comparand)
{
    var valueToReturn = location1;
    if (location1 == comparand)
    {
        location1 = value;
    }

    return valueToReturn;
}

Taken from the docs here: https://learn.microsoft.com/en-us/dotnet/api/system.threading.interlocked.compareexchange

Parameters

  • location1 (Int32)
    The destination, whose value is compared with comparand and possibly replaced.
  • value (Int32)
    The value that replaces the destination value if the comparison results in equality.
  • comparand (Int32)
    The value that is compared to the value at location1.
  • Returns (Int32)
    The original value in location1.

Remarks

If comparand and the value in location1 are equal, then value is stored in location1. Otherwise, no operation is performed. The compare and exchange operations are performed as an atomic operation. The return value of CompareExchange is the original value in location1, whether or not the exchange takes place.

Flydog57
  • 6,851
  • 2
  • 17
  • 18
  • Thanks for duplicating the answer. – Xtros Dec 17 '19 at 23:44
  • Ah, but you edited the answer since I started writing the code. Your original code was wrong. – Flydog57 Dec 17 '19 at 23:45
  • @Flydog57 Thanks that's helped everything fit into place. Next question is: "Why the hell is that the return value!?" (https://stackoverflow.com/questions/59388171/is-there-some-good-reason-for-the-return-value-of-interlocked-compareexchange) – Brondahl Dec 18 '19 at 08:43
  • Uh, why not? The old value would be lost otherwise. You know the values of `value` and `comparand`. The only value that changes is the value of `location1`. Handing it back allows you to save it if you want. – Flydog57 Dec 18 '19 at 12:41
0
int CompareExchange(ref int location1, int value, int comparand)
{
    if (location1 == null)
        throw new ArgumentNullException(nameof(location1));

    if (location1 != comparand)
    {
        return location1;
    }

    int originalValue = location1;
    location1 = value;
    return originalValue;
}
Xtros
  • 467
  • 5
  • 9
  • 2
    A `ref int` cannot be null. The first parameter is ref since it is read (as part of the `if`) and possibly written to. But, it's never null. I also think your logic is wrong. The `if` condition is correct, but the code should simply be `if (location1 == comparand) { location1 = value; }` – Flydog57 Dec 17 '19 at 23:32
  • The documentation for Interlocked.CompareExchange says it throws an ArgumentNullException if location1 is a null pointer. You're right, I do have a mistake, but this is a naive implementation. ;) – Xtros Dec 17 '19 at 23:33
  • @Xtros: that it does (says it throws). But, try compiling your code. You'll get `warning CS0472: The result of the expression is always 'false' since a value of type 'int' is never equal to 'null' of type 'int?'` – Flydog57 Dec 17 '19 at 23:35
  • The intent of the question is to have a rough idea of what Interlocked.CompareExchange does. I can change this to pseudo-code if you like, but this is a rough idea of what it does. – Xtros Dec 17 '19 at 23:36
  • [This question](https://stackoverflow.com/questions/37723030/can-interlocked-compareexchange-throw-nullreferenceexception) provides more information about this technicality of CompareExchange. – Xtros Dec 17 '19 at 23:42