I am implementing an Elimination back-off stack and I'm confronting a problem trying to invoke compareAndSet on AtomicRef.
I have a function called "write":
private fun write(elementRef: E, index: Int): AtomicRef<Any?>? {
val positionRef: AtomicRef<Any?> = eliminationArray[index]
return if (positionRef.compareAndSet(null, elementRef)) {
positionRef
} else null
}
This function returns the AtomicRef to the place where the element was set. (eliminationArray is filled with nulls at the beginning:
private val eliminationArray = atomicArrayOfNulls<Any?>(ELIMINATION_ARRAY_SIZE)
). Inside my method "push" I get positionRef via this function "write":
fun push(x: E) {
val elimIndex = Random.nextInt(ELIMINATION_ARRAY_SIZE)
val positionRef = write(x, elimIndex)
if (positionRef != null) {
for (i in 0 until ELIMINATION_WAIT) {
if (positionRef.compareAndSet(null, null)) {
return
}
}
if (!positionRef.compareAndSet(x, null)) {
return
}
}
...
}
PositionRef is a reference to the place in elimination array where the element was set (or null). If it is not null, I try to invoke compareAndSet, intending to check whether the element was already popped by another thread, changed or stayed the same. If it is not the same, I return, else I execute the code after "if" clause. What I actually get is
Cause: standalone invocation of kotlinx.atomicfu.AtomicRef::compareAndSet that was not traced to previous field load
Obviously it fails on lines with invoking positionRef.compareAndSet(), but why does it happen so and how can I fix it?
P.S. I tried to debug this code and I discovered that during the debugging after the line val positionRef = write(x, elimIndex)
I can execute both positionRef.compareAndSet(null, null)
(result is false) and positionRef.compareAndSet(x, null)
(result is true). So why does it work in debug mode, but not in the runtime?