There is no built-in class that I'm aware of which exactly that
functionality.
in C Sharp? I tried to hack something together:
http://pastebin.com/m16a32c47
But as you can probably see, it's not working. The DWCAS should have
failed, but it erroneously succeeded anyway.
Why should it have failed? You are passing exactly the same object for
the original and the comparand, so of course they will test equal and the
original will be replaced by your "xchg" object.
The implementation of the "DWCAS()" method seems little more to me than an
inefficient, potentially buggy version of the Interlock.CompareExchange()
method it uses. Inefficient, because the if() statement after the
exchange is redundant; first you check for object equality, then you check
for equality of a member in the two objects you already verified as
equal. The latter test, when executed at all, will always evaluate as
"true".
Buggy, because the method is also not thread-safe, in the sense that the
passed-in variables, if accessed by multiple threads, could wind up being
modified by one thread during the execution of the method in another
thread (possibly even by the same method). In fact, there's not any way
for the method itself to be inherently thread-safe; it can only be made
that way through changes to the callers. The method itself doesn't have
enough information about the operands to be made thread-safe. This sort
of "interlocked" operation is all about thread safety, so that's an
obvious problem.
The usefulness of modifying the comparand to be the original value is also
lost on me.
Am I making any obvious mistakes? I need to be able to atomically mutate
an object reference along with an integer. Please help as I am not an
expert in C#!
The biggest issue I see is that the class you created isn't semantically
anything like the Java AtomicStampedReference class. Your class is
basically just a "holder" for data, and you've tried to implement the Java
functionality in a single method elsewhere.
As a first attempt, I would definitely just duplicate the Java class,
rather than change the API at the same time. It's much harder to try to
do two new things at the same time than just one new thing.
Also, you've stated a problem goal that is precisely the behavior of the
Java class. But, it's entirely possible that whatever algorithmic goal
you have is achievable through other means, rather than literally via the
implementation provided using the Java API. Creating new classes to do
exactly what you could do with built-in classes is something one ought to
avoid.
All that said, here's a simple implementation of the Java class, in C#,
that might be suitable for your needs:
class AtomicStampedReference<T>
{
private T _t;
private int _i;
private object _objLock = new object();
public AtomicStampedReference(T tInitial, int iInitial)
{
_t = tInitial;
_i = iInitial;
}
public T Value { get { return _t; } }
public int Stamp { get { return _i; } }
public void GetValueAndStamp(out T tCurrent, out int iCurrent)
{
lock (_objLock)
{
tCurrent = _t;
iCurrent = _i;
}
}
public void SetValueAndStamp(T tNew, int iNew)
{
lock (_objLock)
{
_t = tNew;
_i = iNew;
}
}
public bool AttemptStamp(T tExpected, int iNew)
{
lock (_objLock)
{
if (_t.Equals(tExpected))
{
_i = iNew;
return true;
}
}
return false;
}
public bool CompareAndSet(T tExpected, T tNew, int iExpected, int
iNew)
{
lock (_objLock)
{
if (_t.Equals(tExpected) && _i == iExpected)
{
_t = tNew;
_i = iNew;
return true;
}
}
return false;
}
public bool WeakCompareAndSet(T tExpected, T tNew, int iExpected,
int iNew)
{
if (Monitor.TryEnter(_objLock))
{
try
{
if (_t.Equals(tExpected) && _i == iExpected)
{
_t = tNew;
_i = iNew;
return true;
}
}
finally
{
Monitor.Exit(_objLock);
}
}
return false;
}
}
Important caveats: I have not compiled, never mind tested, the above
code. Inspect and test it carefully to be sure it's suitable for your
needs. Also, in C# be very wary of the difference between
Object.Equals(Object), T.Equals(T), and the == operator. Ideally, these
will be implemented identically (and in most cases for reference types,
the default implementation using reference equality is what's being used),
and so it shouldn't be an issue. But if you start using classes with
custom implementations of those methods and operator, if it's not done
right you can get some weirdly incorrect results.
Pete