[K/N] Stabilization of Atomics API
`AtomicInt`, `AtomicLong`, `AtomicReference` and `AtomicNativePtr` classes were moved to `kotlin.concurrent` package. The corresponding classes from `kotlin.native.concurrent` were deprecated with warning since Kotlin 1.9.
In order to prepare for further commonization of Atomics API the following changes were made:
* `kotlin.concurrent.AtomicInt`:
* `increment(): Unit` and `decrement(): Unit` methods were deprecated with error
* New methods were added: `incrementAndGet(): Int` , `decrementAndGet(): Int`, `getAndIncrement(): Int`, `getAndDecrement(): Int`, `getAndSet(newValue: Int): Int`
* `kotlin.concurrent.AtomicLong`:
* `increment(): Unit` and `decrement(): Unit` methods were deprecated with error
* New methods were added: `incrementAndGet(): Long`, `decrementAndGet(): Long`, `getAndIncrement(): Long`, `getAndDecrement(): Long`, `getAndSet(newValue: Long): Long`
* Deprecated `AtomicLong()` constructor with default parameter value
* For all atomic classes `compareAndSwap` method was renamed to `compareAndExchange`
See KT-58074 for more details.
Merge-request: KT-MR-9272
Merged-by: Maria Sokolova <maria.sokolova@jetbrains.com>
This commit is contained in:
@@ -1,177 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
@file:OptIn(FreezingIsDeprecated::class, ObsoleteWorkersApi::class)
|
||||
package runtime.workers.atomic0
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
fun test1(workers: Array<Worker>) {
|
||||
val atomic = AtomicInt(15)
|
||||
val futures = Array(workers.size, { workerIndex ->
|
||||
workers[workerIndex].execute(TransferMode.SAFE, { atomic }) {
|
||||
input -> input.addAndGet(1)
|
||||
}
|
||||
})
|
||||
futures.forEach {
|
||||
it.result
|
||||
}
|
||||
println(atomic.value)
|
||||
}
|
||||
|
||||
fun test2(workers: Array<Worker>) {
|
||||
val atomic = AtomicInt(1)
|
||||
val counter = AtomicInt(0)
|
||||
val futures = Array(workers.size, { workerIndex ->
|
||||
workers[workerIndex].execute(TransferMode.SAFE, { Triple(atomic, workerIndex, counter) }) {
|
||||
(place, index, result) ->
|
||||
// Here we simulate mutex using [place] location to store tag of the current worker.
|
||||
// When it is negative - worker executes exclusively.
|
||||
val tag = index + 1
|
||||
while (place.compareAndSwap(tag, -tag) != tag) {}
|
||||
val ok1 = result.addAndGet(1) == index + 1
|
||||
// Now, let the next worker run.
|
||||
val ok2 = place.compareAndSwap(-tag, tag + 1) == -tag
|
||||
ok1 && ok2
|
||||
}
|
||||
})
|
||||
futures.forEach {
|
||||
assertEquals(it.result, true)
|
||||
}
|
||||
println(counter.value)
|
||||
}
|
||||
|
||||
data class Data(val value: Int)
|
||||
|
||||
fun test3(workers: Array<Worker>) {
|
||||
val common = AtomicReference<Data?>(null)
|
||||
val futures = Array(workers.size, { workerIndex ->
|
||||
workers[workerIndex].execute(TransferMode.SAFE, { Pair(common, workerIndex) }) {
|
||||
(place, index) ->
|
||||
val mine = Data(index).freeze()
|
||||
// Try to publish our own data, until successful, in a tight loop.
|
||||
while (!place.compareAndSet(null, mine)) {}
|
||||
}
|
||||
})
|
||||
val seen = mutableSetOf<Data>()
|
||||
for (i in 0 until workers.size) {
|
||||
do {
|
||||
val current = common.value
|
||||
if (current != null && !seen.contains(current)) {
|
||||
seen += current
|
||||
// Let others publish.
|
||||
assertEquals(common.compareAndSwap(current, null), current)
|
||||
break
|
||||
}
|
||||
} while (true)
|
||||
}
|
||||
futures.forEach {
|
||||
it.result
|
||||
}
|
||||
assertEquals(seen.size, workers.size)
|
||||
}
|
||||
|
||||
fun test4LegacyMM() {
|
||||
assertFailsWith<InvalidMutabilityException> {
|
||||
AtomicReference(Data(1))
|
||||
}
|
||||
assertFailsWith<InvalidMutabilityException> {
|
||||
AtomicReference<Data?>(null).compareAndSwap(null, Data(2))
|
||||
}
|
||||
}
|
||||
|
||||
fun test4() {
|
||||
run {
|
||||
val ref = AtomicReference(Data(1))
|
||||
assertEquals(1, ref.value.value)
|
||||
}
|
||||
run {
|
||||
val ref = AtomicReference<Data?>(null)
|
||||
ref.compareAndSwap(null, Data(2))
|
||||
assertEquals(2, ref.value!!.value)
|
||||
}
|
||||
if (Platform.isFreezingEnabled) {
|
||||
run {
|
||||
val ref = AtomicReference<Data?>(null).freeze()
|
||||
assertFailsWith<InvalidMutabilityException> {
|
||||
ref.compareAndSwap(null, Data(2))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun test5LegacyMM() {
|
||||
assertFailsWith<InvalidMutabilityException> {
|
||||
AtomicReference<Data?>(null).value = Data(2)
|
||||
}
|
||||
val ref = AtomicReference<Data?>(null)
|
||||
val value = Data(3).freeze()
|
||||
assertEquals(null, ref.value)
|
||||
ref.value = value
|
||||
assertEquals(3, ref.value!!.value)
|
||||
}
|
||||
|
||||
fun test5() {
|
||||
val ref = AtomicReference<Data?>(null)
|
||||
ref.value = Data(2)
|
||||
assertEquals(2, ref.value!!.value)
|
||||
ref.value = Data(3).freeze()
|
||||
assertEquals(3, ref.value!!.value)
|
||||
}
|
||||
|
||||
fun test6() {
|
||||
val int = AtomicInt(0)
|
||||
int.value = 239
|
||||
assertEquals(239, int.value)
|
||||
val long = AtomicLong(0)
|
||||
long.value = 239L
|
||||
assertEquals(239L, long.value)
|
||||
}
|
||||
|
||||
|
||||
fun test7() {
|
||||
val ref = FreezableAtomicReference(Array(1) { "hey" })
|
||||
ref.value[0] = "ho"
|
||||
assertEquals(ref.value[0], "ho")
|
||||
ref.value = Array(1) { "po" }
|
||||
assertEquals(ref.value[0], "po")
|
||||
ref.freeze()
|
||||
if (Platform.isFreezingEnabled) {
|
||||
assertFailsWith<InvalidMutabilityException> {
|
||||
ref.value = Array(1) { "no" }
|
||||
}
|
||||
assertFailsWith<InvalidMutabilityException> {
|
||||
ref.value[0] = "go"
|
||||
}
|
||||
}
|
||||
ref.value = Array(1) { "so" }.freeze()
|
||||
assertEquals(ref.value[0], "so")
|
||||
}
|
||||
|
||||
@Test fun runTest() {
|
||||
val COUNT = 20
|
||||
val workers = Array(COUNT, { _ -> Worker.start()})
|
||||
|
||||
test1(workers)
|
||||
test2(workers)
|
||||
test3(workers)
|
||||
if (Platform.memoryModel == MemoryModel.EXPERIMENTAL) {
|
||||
test4()
|
||||
test5()
|
||||
} else {
|
||||
test4LegacyMM()
|
||||
test5LegacyMM()
|
||||
}
|
||||
test6()
|
||||
test7()
|
||||
|
||||
workers.forEach {
|
||||
it.requestTermination().result
|
||||
}
|
||||
println("OK")
|
||||
}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
35
|
||||
20
|
||||
OK
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
// Note: This test reproduces a race, so it'll start flaking if problem is reintroduced.
|
||||
@file:OptIn(kotlin.native.runtime.NativeRuntimeApi::class)
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.native.internal.*
|
||||
import kotlin.native.runtime.GC
|
||||
|
||||
val thrashGC = AtomicInt(1)
|
||||
val canStartCreating = AtomicInt(0)
|
||||
val createdCount = AtomicInt(0)
|
||||
val canStartReading = AtomicInt(0)
|
||||
const val atomicsCount = 1000
|
||||
const val workersCount = 10
|
||||
|
||||
fun main() {
|
||||
val gcWorker = Worker.start()
|
||||
val future = gcWorker.execute(TransferMode.SAFE, {}, {
|
||||
canStartCreating.value = 1
|
||||
while (thrashGC.value != 0) {
|
||||
GC.collectCyclic()
|
||||
}
|
||||
GC.collect()
|
||||
})
|
||||
|
||||
while (canStartCreating.value == 0) {}
|
||||
|
||||
val workers = Array(workersCount) { Worker.start() }
|
||||
val futures = workers.map {
|
||||
it.execute(TransferMode.SAFE, {}, {
|
||||
val atomics = Array(atomicsCount) {
|
||||
AtomicReference<Any?>(Any().freeze())
|
||||
}
|
||||
createdCount.increment()
|
||||
while (canStartReading.value == 0) {}
|
||||
GC.collect()
|
||||
atomics.all { it.value != null }
|
||||
})
|
||||
}
|
||||
|
||||
while (createdCount.value != workersCount) {}
|
||||
|
||||
thrashGC.value = 0
|
||||
future.result
|
||||
GC.collect()
|
||||
canStartReading.value = 1
|
||||
|
||||
assertTrue(futures.all { it.result })
|
||||
|
||||
for (worker in workers) {
|
||||
worker.requestTermination().result
|
||||
}
|
||||
gcWorker.requestTermination().result
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
@Test
|
||||
fun ctor_Int() {
|
||||
val x = AtomicInt(0)
|
||||
assertEquals(x.value, 0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun ctor_Long() {
|
||||
val x = AtomicLong(0)
|
||||
assertEquals(x.value, 0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun setter_Int() {
|
||||
val x = AtomicInt(0)
|
||||
x.value = 1
|
||||
assertEquals(x.value, 1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun setter_Long() {
|
||||
val x = AtomicLong(0)
|
||||
x.value = 1
|
||||
assertEquals(x.value, 1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun addAndGet_Int() {
|
||||
val x = AtomicInt(1)
|
||||
val result = x.addAndGet(2)
|
||||
assertEquals(result, 1 + 2)
|
||||
assertEquals(x.value, result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun addAndGet_Long() {
|
||||
val x = AtomicLong(1)
|
||||
val result = x.addAndGet(2)
|
||||
assertEquals(result, 1 + 2)
|
||||
assertEquals(x.value, result)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun compareAndSwap_Int() {
|
||||
val x = AtomicInt(0)
|
||||
val successValue = x.compareAndSwap(0, 1)
|
||||
assertEquals(successValue, 0)
|
||||
assertEquals(x.value, 1)
|
||||
val failValue = x.compareAndSwap(0, 2)
|
||||
assertEquals(failValue, 1)
|
||||
assertEquals(x.value, 1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun compareAndSwap_Long() {
|
||||
val x = AtomicLong(0)
|
||||
val successValue = x.compareAndSwap(0, 1)
|
||||
assertEquals(successValue, 0)
|
||||
assertEquals(x.value, 1)
|
||||
val failValue = x.compareAndSwap(0, 2)
|
||||
assertEquals(failValue, 1)
|
||||
assertEquals(x.value, 1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun compareAndSet_Int() {
|
||||
val x = AtomicInt(0)
|
||||
val successValue = x.compareAndSet(0, 1)
|
||||
assertTrue(successValue)
|
||||
assertEquals(x.value, 1)
|
||||
val failValue = x.compareAndSet(0, 2)
|
||||
assertFalse(failValue)
|
||||
assertEquals(x.value, 1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun compareAndSet_Long() {
|
||||
val x = AtomicLong(0)
|
||||
val successValue = x.compareAndSet(0, 1)
|
||||
assertTrue(successValue)
|
||||
assertEquals(x.value, 1)
|
||||
val failValue = x.compareAndSet(0, 2)
|
||||
assertFalse(failValue)
|
||||
assertEquals(x.value, 1)
|
||||
}
|
||||
@@ -9,6 +9,8 @@ package runtime.workers.lazy4
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.concurrent.*
|
||||
import kotlin.concurrent.AtomicInt
|
||||
|
||||
const val WORKERS_COUNT = 20
|
||||
|
||||
@@ -24,7 +26,7 @@ fun concurrentLazyAccess(freeze: Boolean, mode: LazyThreadSafetyMode) {
|
||||
val initializerCallCount = AtomicInt(0)
|
||||
|
||||
val c = C(argumentMode) {
|
||||
initializerCallCount.increment()
|
||||
initializerCallCount.incrementAndGet()
|
||||
IntHolder(42)
|
||||
}
|
||||
if (freeze) {
|
||||
@@ -36,7 +38,7 @@ fun concurrentLazyAccess(freeze: Boolean, mode: LazyThreadSafetyMode) {
|
||||
val canStart = AtomicInt(0)
|
||||
val futures = Array(workers.size) { i ->
|
||||
workers[i].execute(TransferMode.SAFE, { Triple(inited, canStart, c) }) { (inited, canStart, c) ->
|
||||
inited.increment()
|
||||
inited.incrementAndGet()
|
||||
while (canStart.value != 1) {}
|
||||
c.data
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@ package runtime.workers.worker10
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.concurrent.*
|
||||
import kotlin.concurrent.AtomicInt
|
||||
import kotlin.concurrent.AtomicReference
|
||||
import kotlin.native.ref.WeakReference
|
||||
import kotlinx.cinterop.StableRef
|
||||
|
||||
@@ -93,14 +96,14 @@ val semaphore = AtomicInt(0)
|
||||
val worker = Worker.start()
|
||||
val future = worker.execute(TransferMode.SAFE, { null }) {
|
||||
val value = atomicRef.value
|
||||
semaphore.increment()
|
||||
semaphore.incrementAndGet()
|
||||
while (semaphore.value != 2) {}
|
||||
println(value.toString() != "")
|
||||
}
|
||||
while (semaphore.value != 1) {}
|
||||
atomicRef.value = null
|
||||
kotlin.native.runtime.GC.collect()
|
||||
semaphore.increment()
|
||||
semaphore.incrementAndGet()
|
||||
future.result
|
||||
worker.requestTermination().result
|
||||
}
|
||||
@@ -110,14 +113,14 @@ val semaphore = AtomicInt(0)
|
||||
val worker = Worker.start()
|
||||
val future = worker.execute(TransferMode.SAFE, { null }) {
|
||||
val value = stableRef.get()
|
||||
semaphore.increment()
|
||||
semaphore.incrementAndGet()
|
||||
while (semaphore.value != 2) {}
|
||||
println(value.toString() != "")
|
||||
}
|
||||
while (semaphore.value != 1) {}
|
||||
stableRef.dispose()
|
||||
kotlin.native.runtime.GC.collect()
|
||||
semaphore.increment()
|
||||
semaphore.incrementAndGet()
|
||||
future.result
|
||||
worker.requestTermination().result
|
||||
}
|
||||
@@ -133,7 +136,7 @@ val stableHolder1 = StableRef.create(("hello" to "world").freeze())
|
||||
semaphore.value = 0
|
||||
val future = worker.execute(TransferMode.SAFE, { WeakReference(stableHolder1.get()) }) {
|
||||
ensureWeakIs(it, "hello" to "world")
|
||||
semaphore.increment()
|
||||
semaphore.incrementAndGet()
|
||||
while (semaphore.value != 2) {}
|
||||
kotlin.native.runtime.GC.collect()
|
||||
ensureWeakIs(it, null)
|
||||
@@ -141,7 +144,7 @@ val stableHolder1 = StableRef.create(("hello" to "world").freeze())
|
||||
while (semaphore.value != 1) {}
|
||||
stableHolder1.dispose()
|
||||
kotlin.native.runtime.GC.collect()
|
||||
semaphore.increment()
|
||||
semaphore.incrementAndGet()
|
||||
future.result
|
||||
worker.requestTermination().result
|
||||
}
|
||||
@@ -153,7 +156,7 @@ val stableHolder2 = StableRef.create(("hello" to "world").freeze())
|
||||
semaphore.value = 0
|
||||
val future = worker.execute(TransferMode.SAFE, { WeakReference(stableHolder2.get()) }) {
|
||||
val value = it.get()
|
||||
semaphore.increment()
|
||||
semaphore.incrementAndGet()
|
||||
while (semaphore.value != 2) {}
|
||||
kotlin.native.runtime.GC.collect()
|
||||
assertEquals("hello" to "world", value)
|
||||
@@ -161,7 +164,7 @@ val stableHolder2 = StableRef.create(("hello" to "world").freeze())
|
||||
while (semaphore.value != 1) {}
|
||||
stableHolder2.dispose()
|
||||
kotlin.native.runtime.GC.collect()
|
||||
semaphore.increment()
|
||||
semaphore.incrementAndGet()
|
||||
future.result
|
||||
worker.requestTermination().result
|
||||
}
|
||||
@@ -171,15 +174,15 @@ val atomicRef2 = AtomicReference<Any?>(Any().freeze())
|
||||
semaphore.value = 0
|
||||
val worker = Worker.start()
|
||||
val future = worker.execute(TransferMode.SAFE, { null }) {
|
||||
val value = atomicRef2.compareAndSwap(null, null)
|
||||
semaphore.increment()
|
||||
val value = atomicRef2.compareAndExchange(null, null)
|
||||
semaphore.incrementAndGet()
|
||||
while (semaphore.value != 2) {}
|
||||
assertEquals(true, value.toString() != "")
|
||||
}
|
||||
while (semaphore.value != 1) {}
|
||||
atomicRef2.value = null
|
||||
kotlin.native.runtime.GC.collect()
|
||||
semaphore.increment()
|
||||
semaphore.incrementAndGet()
|
||||
future.result
|
||||
worker.requestTermination().result
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ package runtime.workers.worker11
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.concurrent.*
|
||||
import kotlin.concurrent.AtomicInt
|
||||
import kotlinx.cinterop.convert
|
||||
|
||||
data class Job(val index: Int, var input: Int, var counter: Int)
|
||||
@@ -79,7 +81,7 @@ val counters = Array(COUNT) { AtomicInt(0) }
|
||||
workerIndex
|
||||
}) { index ->
|
||||
assertEquals(0, counters[index].value)
|
||||
counters[index].increment()
|
||||
counters[index].incrementAndGet()
|
||||
}
|
||||
}
|
||||
futures2.forEach { it.result }
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
package runtime.workers.worker4
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
import kotlin.native.concurrent.*
|
||||
import kotlin.concurrent.AtomicInt
|
||||
|
||||
@Test fun runTest1() {
|
||||
withWorker {
|
||||
@@ -32,13 +32,14 @@ import kotlin.native.concurrent.*
|
||||
assertTrue(Worker.current.processQueue())
|
||||
assertEquals(1, counter.value)
|
||||
// Let main proceed.
|
||||
counter.increment() // counter becomes 2 here.
|
||||
counter.incrementAndGet() // counter becomes 2 here.
|
||||
assertTrue(Worker.current.park(10_000_000, true))
|
||||
assertEquals(3, counter.value)
|
||||
}.freeze())
|
||||
|
||||
executeAfter(0, {
|
||||
counter.increment()
|
||||
counter.incrementAndGet()
|
||||
Unit
|
||||
}.freeze())
|
||||
|
||||
while (counter.value < 2) {
|
||||
@@ -46,7 +47,8 @@ import kotlin.native.concurrent.*
|
||||
}
|
||||
|
||||
executeAfter(0, {
|
||||
counter.increment()
|
||||
counter.incrementAndGet()
|
||||
Unit
|
||||
}.freeze())
|
||||
|
||||
while (counter.value == 2) {
|
||||
@@ -60,7 +62,8 @@ import kotlin.native.concurrent.*
|
||||
val counter = AtomicInt(0)
|
||||
worker.executeAfter(0, {
|
||||
assertEquals("Lumberjack", Worker.current.name)
|
||||
counter.increment()
|
||||
counter.incrementAndGet()
|
||||
Unit
|
||||
}.freeze())
|
||||
|
||||
while (counter.value == 0) {
|
||||
@@ -76,7 +79,8 @@ import kotlin.native.concurrent.*
|
||||
@Test fun runTest4() {
|
||||
val counter = AtomicInt(0)
|
||||
Worker.current.executeAfter(10_000, {
|
||||
counter.increment()
|
||||
counter.incrementAndGet()
|
||||
Unit
|
||||
}.freeze())
|
||||
assertTrue(Worker.current.park(1_000_000, process = true))
|
||||
assertEquals(1, counter.value)
|
||||
@@ -88,7 +92,8 @@ import kotlin.native.concurrent.*
|
||||
withWorker {
|
||||
executeAfter(1000, {
|
||||
main.executeAfter(1, {
|
||||
counter.increment()
|
||||
counter.incrementAndGet()
|
||||
Unit
|
||||
}.freeze())
|
||||
}.freeze())
|
||||
assertTrue(main.park(1000L * 1000 * 1000, process = true))
|
||||
@@ -106,13 +111,13 @@ import kotlin.native.concurrent.*
|
||||
withWorker {
|
||||
val f1 = execute(TransferMode.SAFE, { counter }) { counter ->
|
||||
Worker.current.park(Long.MAX_VALUE / 1000L, process = true)
|
||||
counter.increment()
|
||||
counter.incrementAndGet()
|
||||
}
|
||||
// wait a bit
|
||||
Worker.current.park(10_000L)
|
||||
// submit a task
|
||||
val f2 = execute(TransferMode.SAFE, { counter }) { counter ->
|
||||
counter.increment()
|
||||
counter.incrementAndGet()
|
||||
}
|
||||
f1.consume {}
|
||||
f2.consume {}
|
||||
@@ -139,14 +144,15 @@ import kotlin.native.concurrent.*
|
||||
|
||||
submitters.forEach {
|
||||
it.executeAfter(0L, {
|
||||
readySubmittersCounter.increment()
|
||||
readySubmittersCounter.incrementAndGet()
|
||||
// Wait for other submitters, to make them all start at the same time:
|
||||
while (readySubmittersCounter.value != numberOfSubmitters) {}
|
||||
|
||||
// Concurrently submit tasks with matching scheduled execution time:
|
||||
repeat(numberOfTasks) {
|
||||
targetWorker.executeAfter(delayInMicroseconds, {
|
||||
executedTasksCounter.increment()
|
||||
executedTasksCounter.incrementAndGet()
|
||||
Unit
|
||||
}.freeze())
|
||||
}
|
||||
|
||||
@@ -157,7 +163,8 @@ import kotlin.native.concurrent.*
|
||||
// the test still might hang without a fix.
|
||||
targetWorker.executeAfter(delayInMicroseconds + 1, {
|
||||
mainWorker.executeAfter(0L, {
|
||||
finishedBatchesCounter.increment()
|
||||
finishedBatchesCounter.incrementAndGet()
|
||||
Unit
|
||||
}.freeze())
|
||||
}.freeze())
|
||||
}.freeze())
|
||||
|
||||
Reference in New Issue
Block a user