Гарантии прогресса
Многие алгоритмы для конкурентного программирования обеспечивают гарантии прогресса, такие как отсутствие блокировок и отсутствие ожидания. Поскольку они обычно нетривиальны, легко добавить ошибку, которая заблокирует алгоритм. Lincheck может помочь найти ошибки живучести, используя стратегию моделирования.
Чтобы проверить гарантию прогресса алгоритма, включите опцию checkObstructionFreedom в ModelCheckingOptions():
ModelCheckingOptions().checkObstructionFreedom()
Создайте файл ConcurrentMapTest.kt. Затем добавьте следующий тест, чтобы обнаружить, что ConcurrentHashMap::put(key: K, value: V) из стандартной библиотеки Java является блокирующей операцией:
import org.jetbrains.kotlinx.lincheck.*
import org.jetbrains.kotlinx.lincheck.annotations.*
import org.jetbrains.kotlinx.lincheck.strategy.managed.modelchecking.*
import org.junit.*
import java.util.concurrent.*
class ConcurrentHashMapTest {
private val map = ConcurrentHashMap<Int, Int>()
@Operation
fun put(key: Int, value: Int) = map.put(key, value)
@Test
fun modelCheckingTest() = ModelCheckingOptions()
.actorsBefore(1) // To init the HashMap
.actorsPerThread(1)
.actorsAfter(0)
.minimizeFailedScenario(false)
.checkObstructionFreedom()
.check(this::class)
}
Запустите modelCheckingTest(). Вы должны получить следующий результат:
= Obstruction-freedom is required but a lock has been found = | ---------------------- | | Thread 1 | Thread 2 | | ---------------------- | | put(1, -1) | | | ---------------------- | | put(2, -2) | put(3, 2) | | ---------------------- | --- All operations above the horizontal line | ----- | happen before those below the line --- The following interleaving leads to the error: | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Thread 1 | Thread 2 | | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | | put(3, 2) | | | put(3,2) at ConcurrentHashMapTest.put(ConcurrentMapTest.kt:11) | | | putVal(3,2,false) at ConcurrentHashMap.put(ConcurrentHashMap.java:1006) | | | table.READ: Node[]@1 at ConcurrentHashMap.putVal(ConcurrentHashMap.java:1014) | | | tabAt(Node[]@1,0): Node@1 at ConcurrentHashMap.putVal(ConcurrentHashMap.java:1018) | | | MONITORENTER at ConcurrentHashMap.putVal(ConcurrentHashMap.java:1031) | | | tabAt(Node[]@1,0): Node@1 at ConcurrentHashMap.putVal(ConcurrentHashMap.java:1032) | | | next.READ: null at ConcurrentHashMap.putVal(ConcurrentHashMap.java:1046) | | | switch | | put(2, -2) | | | put(2,-2) at ConcurrentHashMapTest.put(ConcurrentMapTest.kt:11) | | | putVal(2,-2,false) at ConcurrentHashMap.put(ConcurrentHashMap.java:1006) | | | table.READ: Node[]@1 at ConcurrentHashMap.putVal(ConcurrentHashMap.java:1014) | | | tabAt(Node[]@1,0): Node@1 at ConcurrentHashMap.putVal(ConcurrentHashMap.java:1018) | | | MONITORENTER at ConcurrentHashMap.putVal(ConcurrentHashMap.java:1031) | | | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
Теперь добавим тест для неблокирующей ConcurrentSkipListMap<K, V>, ожидая, что тест пройдет успешно:
class ConcurrentSkipListMapTest {
private val map = ConcurrentSkipListMap<Int, Int>()
@Operation
fun put(key: Int, value: Int) = map.put(key, value)
@Test
fun modelCheckingTest() = ModelCheckingOptions()
.checkObstructionFreedom()
.check(this::class)
}
В настоящее время Lincheck поддерживает только гарантии прогресса obstruction-freedom. Однако большинство реальных ошибок живучести добавляют неожиданный блокирующий код, поэтому проверка obstruction-freedom также поможет с lock-free и wait-free алгоритмами.
Следующий шаг
Узнайте, как указать последовательное описание алгоритма тестирования явно, повышая надёжность тестов Lincheck.
© 2010–2023 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/progress-guarantees.html