Skip to content

Commit fa612f9

Browse files
committed
One more stress test for LockFreeLinkedList (many concurrent operations on a short list)
1 parent 9700de3 commit fa612f9

File tree

2 files changed

+98
-1
lines changed

2 files changed

+98
-1
lines changed
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,12 @@ import java.util.concurrent.atomic.AtomicInteger
2222
import kotlin.concurrent.thread
2323
import kotlin.coroutines.experimental.buildIterator
2424

25-
class LockFreeLinkedListStressTest {
25+
/**
26+
* This stress test has 2 threads adding on one side on list, 2 more threads adding on the other,
27+
* and 6 threads iterating and concurrently removing items. The resulting list that is being
28+
* stressed is long.
29+
*/
30+
class LockFreeLinkedListLongStressTest {
2631
private data class IntNode(val i: Int) : LockFreeLinkedListNode()
2732
private val list = LockFreeLinkedListHead()
2833

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
* Copyright 2016-2017 JetBrains s.r.o.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package kotlinx.coroutines.experimental.internal
18+
19+
import org.junit.Assert.assertEquals
20+
import org.junit.Assert.assertTrue
21+
import org.junit.Test
22+
import java.util.*
23+
import java.util.concurrent.atomic.AtomicInteger
24+
import kotlin.concurrent.thread
25+
26+
/**
27+
* This stress test has 6 threads adding randomly first or last item to the list and them immediately undoing
28+
* this addition by remove, and 4 threads removing first node. The resulting list that is being
29+
* stressed is very short.
30+
*/
31+
class LockFreeLinkedListShortStressTest {
32+
private data class IntNode(val i: Int) : LockFreeLinkedListNode()
33+
private val list = LockFreeLinkedListHead()
34+
35+
val threads = mutableListOf<Thread>()
36+
val nAdderThreads = 6
37+
val nRemoverThreads = 4
38+
val timeout = 5000L
39+
val completedAdder = AtomicInteger()
40+
val completedRemover = AtomicInteger()
41+
42+
val undone = AtomicInteger()
43+
val missed = AtomicInteger()
44+
val removed = AtomicInteger()
45+
46+
@Test
47+
fun testStress() {
48+
val deadline = System.currentTimeMillis() + timeout
49+
repeat(nAdderThreads) { threadId ->
50+
threads += thread(start = false, name = "adder-$threadId") {
51+
val rnd = Random()
52+
while (System.currentTimeMillis() < deadline) {
53+
val node = IntNode(threadId)
54+
when (rnd.nextInt(4)) {
55+
0 -> list.addFirst(node)
56+
1 -> list.addLast(node)
57+
2 -> list.addFirstIf(node, { true }) // just to test conditional add
58+
3 -> list.addLastIf(node, { true })
59+
}
60+
if (node.remove())
61+
undone.incrementAndGet()
62+
else
63+
missed.incrementAndGet()
64+
}
65+
completedAdder.incrementAndGet()
66+
}
67+
}
68+
repeat(nRemoverThreads) { threadId ->
69+
threads += thread(start = false, name = "remover-$threadId") {
70+
while (System.currentTimeMillis() < deadline) {
71+
val node = list.removeFirstOrNull()
72+
if (node != null) removed.incrementAndGet()
73+
74+
}
75+
completedRemover.incrementAndGet()
76+
}
77+
}
78+
threads.forEach { it.start() }
79+
threads.forEach { it.join() }
80+
println("Completed successfully ${completedAdder.get()} adder threads")
81+
println("Completed successfully ${completedRemover.get()} remover threads")
82+
println(" Adders undone ${undone.get()} node additions")
83+
println(" Adders missed ${missed.get()} nodes")
84+
println("Remover removed ${removed.get()} nodes")
85+
assertEquals(nAdderThreads, completedAdder.get())
86+
assertEquals(nRemoverThreads, completedRemover.get())
87+
assertEquals(missed.get(), removed.get())
88+
assertTrue(undone.get() > 0)
89+
assertTrue(missed.get() > 0)
90+
list.validate()
91+
}
92+
}

0 commit comments

Comments
 (0)