Concurrent API update. (#1949)
This commit is contained in:
@@ -14,7 +14,7 @@ import kotlin.test.*
|
||||
@Test
|
||||
fun testRandomWorkers() {
|
||||
val seed = getTimeMillis()
|
||||
val workers = Array(5, { _ -> startWorker()})
|
||||
val workers = Array(5, { _ -> Worker.start() })
|
||||
|
||||
val attempts = 3
|
||||
val results = Array(attempts, { ArrayList<Int>() } )
|
||||
@@ -22,7 +22,8 @@ fun testRandomWorkers() {
|
||||
Random.seed = seed
|
||||
// Produce a list of random numbers in each worker
|
||||
val futures = Array(workers.size, { workerIndex ->
|
||||
workers[workerIndex].schedule(TransferMode.CHECKED, { workerIndex }) { input ->
|
||||
workers[workerIndex].execute(TransferMode.SAFE, { workerIndex }) {
|
||||
input ->
|
||||
Array(10, { Random.nextInt() }).toList()
|
||||
}
|
||||
})
|
||||
@@ -30,11 +31,11 @@ fun testRandomWorkers() {
|
||||
val futureSet = futures.toSet()
|
||||
for (i in 0 until futureSet.size) {
|
||||
val ready = futureSet.waitForMultipleFutures(10000)
|
||||
ready.forEach { results[attempt].addAll(it.result()) }
|
||||
ready.forEach { results[attempt].addAll(it.result) }
|
||||
}
|
||||
}
|
||||
|
||||
workers.forEach {
|
||||
it.requestTermination().consume { _ -> }
|
||||
it.requestTermination().result
|
||||
}
|
||||
}
|
||||
@@ -12,54 +12,54 @@ import kotlin.native.concurrent.*
|
||||
fun test1(workers: Array<Worker>) {
|
||||
val atomic = AtomicInt(15)
|
||||
val futures = Array(workers.size, { workerIndex ->
|
||||
workers[workerIndex].schedule(TransferMode.CHECKED, { atomic }) {
|
||||
input -> input.increment()
|
||||
workers[workerIndex].execute(TransferMode.SAFE, { atomic }) {
|
||||
input -> input.addAndGet(1)
|
||||
}
|
||||
})
|
||||
futures.forEach {
|
||||
it.result()
|
||||
it.result
|
||||
}
|
||||
println(atomic.get())
|
||||
println(atomic.value)
|
||||
}
|
||||
|
||||
fun test2(workers: Array<Worker>) {
|
||||
val atomic = AtomicInt(1)
|
||||
val counter = AtomicInt(0)
|
||||
val futures = Array(workers.size, { workerIndex ->
|
||||
workers[workerIndex].schedule(TransferMode.CHECKED, { Triple(atomic, workerIndex, counter) }) {
|
||||
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.increment() == index + 1
|
||||
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)
|
||||
assertEquals(it.result, true)
|
||||
}
|
||||
println(counter.get())
|
||||
println(counter.value)
|
||||
}
|
||||
|
||||
data class Data(val value: Int)
|
||||
|
||||
fun test3(workers: Array<Worker>) {
|
||||
val common = AtomicReference<Data>()
|
||||
val common = AtomicReference<Data?>(null)
|
||||
val futures = Array(workers.size, { workerIndex ->
|
||||
workers[workerIndex].schedule(TransferMode.CHECKED, { Pair(common, 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.compareAndSwap(null, mine) != null) {}
|
||||
while (!place.compareAndSet(null, mine)) {}
|
||||
}
|
||||
})
|
||||
val seen = mutableSetOf<Data>()
|
||||
for (i in 0 until workers.size) {
|
||||
do {
|
||||
val current = common.get()
|
||||
val current = common.value
|
||||
if (current != null && !seen.contains(current)) {
|
||||
seen += current
|
||||
// Let others publish.
|
||||
@@ -69,7 +69,7 @@ fun test3(workers: Array<Worker>) {
|
||||
} while (true)
|
||||
}
|
||||
futures.forEach {
|
||||
it.result()
|
||||
it.result
|
||||
}
|
||||
assertEquals(seen.size, workers.size)
|
||||
}
|
||||
@@ -79,33 +79,33 @@ fun test4() {
|
||||
AtomicReference(Data(1))
|
||||
}
|
||||
assertFailsWith<InvalidMutabilityException> {
|
||||
AtomicReference<Data>().compareAndSwap(null, Data(2))
|
||||
AtomicReference<Data?>(null).compareAndSwap(null, Data(2))
|
||||
}
|
||||
}
|
||||
|
||||
fun test5() {
|
||||
assertFailsWith<InvalidMutabilityException> {
|
||||
AtomicReference<Data>().set(Data(2))
|
||||
AtomicReference<Data?>(null).value = Data(2)
|
||||
}
|
||||
val ref = AtomicReference<Data>()
|
||||
val ref = AtomicReference<Data?>(null)
|
||||
val value = Data(3).freeze()
|
||||
assertEquals(null, ref.get())
|
||||
ref.set(value)
|
||||
assertEquals(3, ref.get()!!.value)
|
||||
assertEquals(null, ref.value)
|
||||
ref.value = value
|
||||
assertEquals(3, ref.value!!.value)
|
||||
}
|
||||
|
||||
fun test6() {
|
||||
val int = AtomicInt()
|
||||
int.set(239)
|
||||
assertEquals(239, int.get())
|
||||
val long = AtomicLong()
|
||||
long.set(239L)
|
||||
assertEquals(239L, long.get())
|
||||
val int = AtomicInt(0)
|
||||
int.value = 239
|
||||
assertEquals(239, int.value)
|
||||
val long = AtomicLong(0)
|
||||
long.value = 239L
|
||||
assertEquals(239L, long.value)
|
||||
}
|
||||
|
||||
@Test fun runTest() {
|
||||
val COUNT = 20
|
||||
val workers = Array(COUNT, { _ -> startWorker()})
|
||||
val workers = Array(COUNT, { _ -> Worker.start()})
|
||||
|
||||
test1(workers)
|
||||
test2(workers)
|
||||
@@ -115,7 +115,7 @@ fun test6() {
|
||||
test6()
|
||||
|
||||
workers.forEach {
|
||||
it.requestTermination().consume { _ -> }
|
||||
it.requestTermination().result
|
||||
}
|
||||
println("OK")
|
||||
}
|
||||
@@ -17,8 +17,8 @@ data class Foo(val kind: A)
|
||||
// Enums are shared between threads so identity should be kept.
|
||||
@Test
|
||||
fun runTest() {
|
||||
val result = startWorker().schedule(TransferMode.CHECKED, { Foo(A.B) }, { input ->
|
||||
val result = Worker.start().execute(TransferMode.SAFE, { Foo(A.B) }, { input ->
|
||||
input.kind == A.B
|
||||
}).result()
|
||||
}).result
|
||||
println(result)
|
||||
}
|
||||
@@ -14,12 +14,12 @@ data class SharedDataMember(val double: Double)
|
||||
data class SharedData(val string: String, val int: Int, val member: SharedDataMember)
|
||||
|
||||
@Test fun runTest() {
|
||||
val worker = startWorker()
|
||||
val worker = Worker.start()
|
||||
// Create immutable shared data.
|
||||
val immutable = SharedData("Hello", 10, SharedDataMember(0.1)).freeze()
|
||||
println("frozen bit is ${immutable.isFrozen}")
|
||||
|
||||
val future = worker.schedule(TransferMode.CHECKED, { immutable } ) {
|
||||
val future = worker.execute(TransferMode.SAFE, { immutable } ) {
|
||||
input ->
|
||||
println("Worker: $input")
|
||||
input
|
||||
@@ -27,6 +27,6 @@ data class SharedData(val string: String, val int: Int, val member: SharedDataMe
|
||||
future.consume {
|
||||
result -> println("Main: $result")
|
||||
}
|
||||
worker.requestTermination().result()
|
||||
worker.requestTermination().result
|
||||
println("OK")
|
||||
}
|
||||
@@ -59,32 +59,32 @@ data class Data(var int: Int)
|
||||
assertFailsWith<InvalidMutabilityException> { a8[1] = 2.0 }
|
||||
|
||||
// Ensure that String and integral boxes are frozen by default, by passing local to the worker.
|
||||
val worker = startWorker()
|
||||
val worker = Worker.start()
|
||||
var data: Any = "Hello" + " " + "world"
|
||||
assert(data.isFrozen)
|
||||
worker.schedule(TransferMode.CHECKED, { data } ) {
|
||||
worker.execute(TransferMode.SAFE, { data } ) {
|
||||
input -> println("Worker 1: $input")
|
||||
}.result()
|
||||
}.result
|
||||
|
||||
data = 42
|
||||
assert(data.isFrozen)
|
||||
worker.schedule(TransferMode.CHECKED, { data } ) {
|
||||
worker.execute(TransferMode.SAFE, { data } ) {
|
||||
input -> println("Worker2: $input")
|
||||
}.result()
|
||||
}.result
|
||||
|
||||
data = 239.0
|
||||
assert(data.isFrozen)
|
||||
worker.schedule(TransferMode.CHECKED, { data } ) {
|
||||
worker.execute(TransferMode.SAFE, { data } ) {
|
||||
input -> println("Worker3: $input")
|
||||
}.result()
|
||||
}.result
|
||||
|
||||
data = 'a'
|
||||
assert(data.isFrozen)
|
||||
worker.schedule(TransferMode.CHECKED, { data } ) {
|
||||
worker.execute(TransferMode.SAFE, { data } ) {
|
||||
input -> println("Worker4: $input")
|
||||
}.result()
|
||||
}.result
|
||||
|
||||
worker.requestTermination().result()
|
||||
worker.requestTermination().result
|
||||
|
||||
println("OK")
|
||||
}
|
||||
@@ -36,9 +36,9 @@ fun testSingleData(workers: Array<Worker>) {
|
||||
val set = mutableSetOf<Any?>()
|
||||
for (attempt in 1 .. 3) {
|
||||
val futures = Array(workers.size, { workerIndex ->
|
||||
workers[workerIndex].schedule(TransferMode.CHECKED, { "" }) { _ -> Immutable2.y }
|
||||
workers[workerIndex].execute(TransferMode.SAFE, { "" }) { _ -> Immutable2.y }
|
||||
})
|
||||
futures.forEach { set += it.result() }
|
||||
futures.forEach { set += it.result }
|
||||
}
|
||||
assertEquals(set.size, 1)
|
||||
assertEquals(set.single(), Immutable2.y)
|
||||
@@ -48,9 +48,9 @@ fun testFrozenLazy(workers: Array<Worker>) {
|
||||
val set = mutableSetOf<Int>()
|
||||
for (attempt in 1 .. 3) {
|
||||
val futures = Array(workers.size, { workerIndex ->
|
||||
workers[workerIndex].schedule(TransferMode.CHECKED, { "" }) { _ -> Immutable3.x }
|
||||
workers[workerIndex].execute(TransferMode.SAFE, { "" }) { _ -> Immutable3.x }
|
||||
})
|
||||
futures.forEach { set += it.result() }
|
||||
futures.forEach { set += it.result }
|
||||
}
|
||||
assertEquals(1, set.size)
|
||||
assertEquals(Immutable3.x, set.single())
|
||||
@@ -77,7 +77,7 @@ fun testLiquidLazy() {
|
||||
assertEquals(42, Immutable.x)
|
||||
|
||||
val COUNT = 5
|
||||
val workers = Array(COUNT, { _ -> startWorker()})
|
||||
val workers = Array(COUNT, { _ -> Worker.start()})
|
||||
testSingleData(workers)
|
||||
testFrozenLazy(workers)
|
||||
testLiquidLazy()
|
||||
|
||||
@@ -10,13 +10,13 @@ import kotlin.test.*
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
@Test fun runTest() {
|
||||
val worker = startWorker()
|
||||
val future = worker.schedule(TransferMode.CHECKED, { "Input" }) {
|
||||
val worker = Worker.start()
|
||||
val future = worker.execute(TransferMode.SAFE, { "Input" }) {
|
||||
input -> input + " processed"
|
||||
}
|
||||
future.consume {
|
||||
result -> println("Got $result")
|
||||
}
|
||||
worker.requestTermination().consume { _ -> }
|
||||
worker.requestTermination().result
|
||||
println("OK")
|
||||
}
|
||||
@@ -11,11 +11,11 @@ import kotlin.native.concurrent.*
|
||||
|
||||
@Test fun runTest() {
|
||||
val COUNT = 5
|
||||
val workers = Array(COUNT, { _ -> startWorker()})
|
||||
val workers = Array(COUNT, { _ -> Worker.start()})
|
||||
|
||||
for (attempt in 1 .. 3) {
|
||||
val futures = Array(workers.size,
|
||||
{ i -> workers[i].schedule(TransferMode.CHECKED, { "$attempt: Input $i" })
|
||||
{ i -> workers[i].execute(TransferMode.SAFE, { "$attempt: Input $i" })
|
||||
{ input -> input + " processed" }
|
||||
})
|
||||
futures.forEachIndexed { index, future ->
|
||||
@@ -29,7 +29,7 @@ import kotlin.native.concurrent.*
|
||||
}
|
||||
}
|
||||
workers.forEach {
|
||||
it.requestTermination().consume { _ -> }
|
||||
it.requestTermination().result
|
||||
}
|
||||
println("OK")
|
||||
}
|
||||
@@ -14,10 +14,10 @@ data class WorkerResult(val intResult: Int, val stringResult: String)
|
||||
|
||||
@Test fun runTest() {
|
||||
val COUNT = 5
|
||||
val workers = Array(COUNT, { _ -> startWorker()})
|
||||
val workers = Array(COUNT, { _ -> Worker.start()})
|
||||
|
||||
for (attempt in 1 .. 3) {
|
||||
val futures = Array(workers.size, { workerIndex -> workers[workerIndex].schedule(TransferMode.CHECKED, {
|
||||
val futures = Array(workers.size, { workerIndex -> workers[workerIndex].execute(TransferMode.SAFE, {
|
||||
WorkerArgument(workerIndex, "attempt $attempt") }) { input ->
|
||||
var sum = 0
|
||||
for (i in 0..input.intParam * 1000) {
|
||||
@@ -33,12 +33,13 @@ data class WorkerResult(val intResult: Int, val stringResult: String)
|
||||
ready.forEach {
|
||||
it.consume { result ->
|
||||
if (result.stringResult != "attempt $attempt result") throw Error("Unexpected $result")
|
||||
consumed++ }
|
||||
consumed++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
workers.forEach {
|
||||
it.requestTermination().consume { _ -> }
|
||||
it.requestTermination().result
|
||||
}
|
||||
println("OK")
|
||||
}
|
||||
@@ -18,19 +18,19 @@ data class WorkerResult(val intResult: Int, val stringResult: String)
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val worker = startWorker()
|
||||
val worker = Worker.start()
|
||||
val dataParam = DataParam(17)
|
||||
val future = try {
|
||||
worker.schedule(TransferMode.CHECKED,
|
||||
{ WorkerArgument(42, dataParam) },
|
||||
{ input -> WorkerResult(input.intParam, input.dataParam.toString() + " result") }
|
||||
)
|
||||
worker.execute(TransferMode.SAFE,
|
||||
{ WorkerArgument(42, dataParam) }) {
|
||||
input -> WorkerResult(input.intParam, input.dataParam.toString() + " result")
|
||||
}
|
||||
} catch (e: IllegalStateException) {
|
||||
null
|
||||
}
|
||||
if (future != null)
|
||||
println("Fail 1")
|
||||
if (dataParam.int != 17) println("Fail 2")
|
||||
worker.requestTermination().consume { _ -> }
|
||||
worker.requestTermination().result
|
||||
println("OK")
|
||||
}
|
||||
@@ -10,13 +10,13 @@ import kotlin.test.*
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
@Test fun runTest() {
|
||||
val worker = startWorker()
|
||||
val future = worker.schedule(TransferMode.CHECKED, { 41 }) {
|
||||
val worker = Worker.start()
|
||||
val future = worker.execute(TransferMode.SAFE, { 41 }) {
|
||||
input -> input + 1
|
||||
}
|
||||
future.consume {
|
||||
result -> println("Got $result")
|
||||
}
|
||||
worker.requestTermination().consume { _ -> }
|
||||
worker.requestTermination().result
|
||||
println("OK")
|
||||
}
|
||||
@@ -10,13 +10,13 @@ import kotlin.test.*
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
@Test fun runTest() {
|
||||
val worker = startWorker()
|
||||
val future = worker.schedule(TransferMode.CHECKED, { "zzz" }) {
|
||||
val worker = Worker.start()
|
||||
val future = worker.execute(TransferMode.SAFE, { "zzz" }) {
|
||||
input -> input.length
|
||||
}
|
||||
future.consume {
|
||||
result -> println("Got $result")
|
||||
}
|
||||
worker.requestTermination().consume { _ -> }
|
||||
worker.requestTermination().result
|
||||
println("OK")
|
||||
}
|
||||
@@ -10,13 +10,13 @@ import kotlin.test.*
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
@Test fun runTest() {
|
||||
val worker = startWorker()
|
||||
val future = worker.schedule(TransferMode.CHECKED, { 42 }) {
|
||||
val worker = Worker.start()
|
||||
val future = worker.execute(TransferMode.SAFE, { 42 }) {
|
||||
input -> input.toString()
|
||||
}
|
||||
future.consume {
|
||||
result -> println("Got $result")
|
||||
}
|
||||
worker.requestTermination().consume { _ -> }
|
||||
worker.requestTermination().result
|
||||
println("OK")
|
||||
}
|
||||
@@ -10,13 +10,13 @@ import kotlin.test.*
|
||||
import kotlin.native.concurrent.*
|
||||
|
||||
@Test fun runTest() {
|
||||
val worker = startWorker()
|
||||
val future = worker.schedule(TransferMode.CHECKED, { "Input" }) {
|
||||
val worker = Worker.start()
|
||||
val future = worker.execute(TransferMode.SAFE, { "Input" }) {
|
||||
input -> println(input)
|
||||
}
|
||||
future.consume {
|
||||
result -> println("Got $result")
|
||||
}
|
||||
worker.requestTermination().consume { _ -> }
|
||||
worker.requestTermination().result
|
||||
println("OK")
|
||||
}
|
||||
@@ -14,19 +14,19 @@ data class SharedDataMember(val double: Double)
|
||||
data class SharedData(val string: String, val int: Int, val member: SharedDataMember)
|
||||
|
||||
@Test fun runTest() {
|
||||
val worker = startWorker()
|
||||
val worker = Worker.start()
|
||||
// Here we do rather strange thing. To test object detach API we detach object graph,
|
||||
// pass C pointer as a value to worker, where we manually reattached passed value.
|
||||
val future = worker.schedule(TransferMode.CHECKED, {
|
||||
detachObjectGraph { SharedData("Hello", 10, SharedDataMember(0.1)) }
|
||||
} ) {
|
||||
inputC ->
|
||||
val input = attachObjectGraph<SharedData>(inputC)
|
||||
// pass detached graph to a worker, where we manually reattached passed value.
|
||||
val future = worker.execute(TransferMode.SAFE, {
|
||||
DetachedObjectGraph { SharedData("Hello", 10, SharedDataMember(0.1)) }.asCPointer()
|
||||
}) {
|
||||
inputDetached ->
|
||||
val input = DetachedObjectGraph<SharedData>(inputDetached).attach()
|
||||
println(input)
|
||||
}
|
||||
future.consume {
|
||||
result -> println("Got $result")
|
||||
}
|
||||
worker.requestTermination().consume { _ -> }
|
||||
worker.requestTermination().result
|
||||
println("OK")
|
||||
}
|
||||
@@ -11,14 +11,14 @@ import kotlin.native.concurrent.*
|
||||
|
||||
@Test fun runTest() {
|
||||
withLock { println("zzz") }
|
||||
val worker = startWorker()
|
||||
val future = worker.schedule(TransferMode.CHECKED, {}) {
|
||||
val worker = Worker.start()
|
||||
val future = worker.execute(TransferMode.SAFE, {}) {
|
||||
withLock {
|
||||
println("42")
|
||||
}
|
||||
}
|
||||
future.result()
|
||||
worker.requestTermination().result()
|
||||
future.result
|
||||
worker.requestTermination().result
|
||||
println("OK")
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user