Skip to content

Commit

Permalink
Implement stack with elimination
Browse files Browse the repository at this point in the history
  • Loading branch information
aartdem committed May 5, 2024
1 parent 175105c commit e179416
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package stack.elimination

import stack.common.ConcurrentStack
import stack.common.Node
import java.util.concurrent.atomic.AtomicReference

class ConcurrentStackWithElimination<T> : ConcurrentStack<T> {
private val eliminationArray = EliminationArray<T>()
private val head = AtomicReference<Node<T>?>()

override fun push(x: T) {
while (true) {
val oldHead = head.get()
val newHead = Node(x, oldHead)
if (head.compareAndSet(oldHead, newHead)) {
return
}
val visitResult = eliminationArray.visit(x)
if (visitResult.isSuccess && visitResult.getOrNull() == null) {
return
}
}
}

override fun pop(): T? {
while (true) {
val oldHead = head.get() ?: return null
val newHead = oldHead.next
if (head.compareAndSet(oldHead, newHead)) {
return oldHead.value
}
val visitResult = eliminationArray.visit(null)
if (visitResult.isSuccess && visitResult.getOrNull() != null) {
return visitResult.getOrNull()
}
}
}

override fun top(): T? = head.get()?.value
}


17 changes: 17 additions & 0 deletions work1/src/main/kotlin/stack/elimination/EliminationArray.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package stack.elimination

import kotlin.random.Random

class EliminationArray<T>(
private val capacity: Int = 10,
private val maxAttemptsCount: Long = 50,
randomSeed: Long = System.currentTimeMillis()
) {
private val exchanger = Array<LockFreeExchanger<T>>(capacity) { LockFreeExchanger() }
private val random = Random(randomSeed)

fun visit(value: T?): Result<T?> {
val slot = random.nextInt(capacity)
return exchanger[slot].exchange(value, maxAttemptsCount)
}
}
48 changes: 48 additions & 0 deletions work1/src/main/kotlin/stack/elimination/LockFreeExchanger.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package stack.elimination

import java.util.concurrent.TimeoutException
import java.util.concurrent.atomic.AtomicStampedReference

class LockFreeExchanger<T> {
private enum class State {
EMPTY, WAITING, BUSY
}

private val slot = AtomicStampedReference<T>(null, State.EMPTY.ordinal)
fun exchange(myItem: T?, maxAttemptsCount: Long): Result<T?> {
val stampHolder = IntArray(1) { State.EMPTY.ordinal }
var i = 0
while (i < maxAttemptsCount) {
var yrItem = slot.get(stampHolder)
when (stampHolder[0]) {
State.EMPTY.ordinal -> {
if (slot.compareAndSet(yrItem, myItem, State.EMPTY.ordinal, State.WAITING.ordinal)) {
while (i < maxAttemptsCount) {
yrItem = slot.get(stampHolder)
if (stampHolder[0] == State.BUSY.ordinal) {
slot.set(null, State.EMPTY.ordinal)
return Result.success(yrItem)
}
i++
}
if (slot.compareAndSet(myItem, null, State.WAITING.ordinal, State.EMPTY.ordinal)) {
return Result.failure(TimeoutException())
} else {
yrItem = slot.get(stampHolder)
slot.set(null, State.EMPTY.ordinal)
return Result.success(yrItem)
}
}
}

State.WAITING.ordinal -> {
if (slot.compareAndSet(yrItem, myItem, State.WAITING.ordinal, State.BUSY.ordinal)) {
return Result.success(yrItem)
}
}
}
i++
}
return Result.failure(TimeoutException())
}
}
5 changes: 4 additions & 1 deletion work1/src/test/kotlin/stack/ConcurrentStackTests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import org.jetbrains.kotlinx.lincheck.check
import org.jetbrains.kotlinx.lincheck.strategy.managed.modelchecking.ModelCheckingOptions
import org.jetbrains.kotlinx.lincheck.strategy.stress.StressOptions
import stack.common.ConcurrentStack
import stack.elimination.ConcurrentStackWithElimination
import stack.simple.ConcurrentTreiberStack
import kotlin.test.Test

Expand Down Expand Up @@ -47,4 +48,6 @@ abstract class ConcurrentStackTests(private val stack: ConcurrentStack<Int>) {
.check(this::class)
}

class ConcurrentTreiberStackTests : ConcurrentStackTests(ConcurrentTreiberStack())
class ConcurrentTreiberStackTests : ConcurrentStackTests(ConcurrentTreiberStack())

class ConcurrentStackWithEliminationTests : ConcurrentStackTests(ConcurrentStackWithElimination())

0 comments on commit e179416

Please sign in to comment.