Гарантии прогресса
Многие параллельные алгоритмы обеспечивают гарантии неблокирующего прогресса, такие как wait-freedom, lock-freedom или obstruction-freedom.
Lincheck поддерживает проверку только obstruction-freedom. Однако, поскольку алгоритмы lock-free и wait-free также обладают obstruction-freedom, любое нарушение obstruction-freedom указывает и на нарушение этих более строгих гарантий.
Используйте параметр checkObstructionFreedom, чтобы проверить гарантию obstruction-freedom программы:
@Test
fun modelCheckingTest() = ModelCheckingOptions()
.checkObstructionFreedom()
.check(this::class)
Lincheck проверяет obstruction-freedom, выясняя, может ли поток продвигаться, когда все остальные потоки приостановлены. Если выполнение потока зацикливается, Lincheck сообщает об активной блокировке.
Если некоторые функции намеренно блокируют выполнение, их можно пометить параметром @Operation(blocking = true), чтобы избежать ложных срабатываний.
Пример: проверка ConcurrentHashMap на obstruction-freedom
В этом примере вы проверите функцию put() структуры ConcurrentHashMap.
Создайте файл
ConcurrentHashMapTest.kt.-
Создайте тестовый класс для
ConcurrentHashMap, объявите функциюput()и тестовую функцию с включенным параметромcheckObstructionFreedom():class ConcurrentHashMapTest { private val map = ConcurrentHashMap<Int, Int>() @Operation fun put(key: Int, value: Int) = map.put(key, value) @Test fun modelCheckingTest() = ModelCheckingOptions() .checkObstructionFreedom() .threads(2) .actorsPerThread(1) .check(this::class) }Параметры
threadsиactorsPerThreadиспользуются для сокращения числа возможных сценариев выполнения. Эти параметры не влияют на результат теста, но значительно сокращают время тестирования. -
Запустите тест. Он должен завершиться с ошибкой и вывести следующий отчет:
= The algorithm should be non-blocking, but an active lock is detected = | --------------------- | | Thread 1 | Thread 2 | | --------------------- | | put(1, 0) | put(1, 1) | | --------------------- | The following interleaving leads to the error: | -------------------------------------------------------------------------------------------------------------- | | Thread 1 | Thread 2 | | -------------------------------------------------------------------------------------------------------------- | | put(1, 0): <hung> | | | map.put(1, 0) | | | putVal(1, 0, false) | | | spread(1): 1 | | | table ➜ null | | | loop(1 iterations) at ConcurrentHashMap.putVal(ConcurrentHashMap.java:1016) | | | <iteration 1> | | | initTable() | | | loop(1 iterations) at ConcurrentHashMap.initTable(ConcurrentHashMap.java:2293) | | | table ➜ null | | | switch | | | | put(1, 1): <hung> | | -------------------------------------------------------------------------------------------------------------- |
-
Добавьте параметр
blocking = trueв аннотацию функцииput():@Operation(blocking = true) fun put(key: Int, value: Int) = map.put(key, value) Запустите тест повторно. Он должен завершиться успешно.
Пример: проверка ConcurrentSkipListMap на obstruction-freedom
В этом примере вы проверите функцию put() неблокирующей структуры ConcurrentSkipListMap.
Создайте файл
ConcurrentSkipListMapTest.kt.-
Создайте тестовый класс для
ConcurrentSkipListMap, объявите функциюput()и тестовую функцию с включенным параметромcheckObstructionFreedom():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) } Запустите тест. Он должен завершиться успешно.
См. также
© 2010–2026 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/lincheck-progress-guarantees.html