Skip to content

Commit c965081

Browse files
committed
swap concurrent Task2/Task3
1 parent 1abb407 commit c965081

File tree

4 files changed

+161
-161
lines changed

4 files changed

+161
-161
lines changed
Lines changed: 15 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,78 +1,23 @@
11
package cub.concurrent.answers
22

3-
import kotlin.concurrent.*
4-
import java.util.concurrent.locks.*
5-
6-
/*
7-
* Implement simple thread-safe blocking stack.
8-
* Use usual mutable list as an underlying storage.
9-
*
10-
* Methods can block the calling thread if they are executed concurrently with other methods.
11-
* Additionally, pop operation can also block the thread if the stack is empty ---
12-
* in this case it should wait until some value will be pushed to the stack.
13-
*/
14-
class SynchronizedBlockingStack<T> {
15-
private val list = mutableListOf<T>()
16-
private val lock = ReentrantLock()
17-
private val condition = lock.newCondition()
18-
19-
fun push(value: T) = lock.withLock {
20-
list.add(value)
21-
condition.signal()
22-
}
23-
24-
fun pop(): T = lock.withLock {
25-
while (list.isEmpty()) {
26-
condition.await()
3+
import java.util.concurrent.ConcurrentLinkedQueue
4+
import kotlin.concurrent.thread
5+
6+
fun<T> Collection<T>.parallelForEach(nThreads: Int, block: (T) -> Unit) {
7+
require(nThreads > 0) { "The number of threads must be > 0" }
8+
val queue = ConcurrentLinkedQueue(this)
9+
val threadPool = (0 until nThreads).map { _ ->
10+
thread {
11+
while (true) {
12+
block(queue.poll() ?: return@thread)
13+
}
2714
}
28-
list.removeLast()
29-
}
30-
31-
fun top(): T? = lock.withLock {
32-
list.lastOrNull()
33-
}
34-
35-
fun size(): Int = lock.withLock {
36-
list.size
37-
}
38-
}
39-
40-
fun test1() {
41-
val stack = SynchronizedBlockingStack<Int>()
42-
thread {
43-
stack.push(1)
44-
}
45-
thread {
46-
stack.push(2)
47-
stack.push(3)
48-
}
49-
thread {
50-
val a = stack.pop()
51-
val b = stack.pop()
52-
val c = stack.pop()
53-
println("a=$a, b=$b, c=$c")
54-
// can print either:
55-
// a=3, b=2, a=1
56-
// a=1, b=3, c=2
57-
// a=3, b=1, a=2
5815
}
59-
}
60-
61-
fun test2() {
62-
val stack = SynchronizedBlockingStack<Int>()
63-
thread {
64-
println("push(1)")
65-
stack.push(1)
66-
}
67-
thread {
68-
val r = stack.pop()
69-
println("pop(): $r")
70-
}
71-
// can only print lines in the following sequence:
72-
// push(1), pop():1
16+
threadPool.forEach { it.join() }
7317
}
7418

7519
fun main() {
76-
test1()
77-
test2()
20+
(1 .. 10).toList().parallelForEach(4) { i ->
21+
println("${i * i}")
22+
}
7823
}
Lines changed: 70 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,78 @@
11
package cub.concurrent.answers
22

3-
import java.util.concurrent.ConcurrentLinkedQueue
4-
import kotlin.concurrent.thread
5-
6-
fun<T> Collection<T>.parallelForEach(nThreads: Int, block: (T) -> Unit) {
7-
require(nThreads > 0) { "The number of threads must be > 0" }
8-
val queue = ConcurrentLinkedQueue(this)
9-
val threadPool = (0 until nThreads).map { _ ->
10-
thread {
11-
while (true) {
12-
block(queue.poll() ?: return@thread)
13-
}
3+
import kotlin.concurrent.*
4+
import java.util.concurrent.locks.*
5+
6+
/*
7+
* Implement simple thread-safe blocking stack.
8+
* Use usual mutable list as an underlying storage.
9+
*
10+
* Methods can block the calling thread if they are executed concurrently with other methods.
11+
* Additionally, pop operation can also block the thread if the stack is empty ---
12+
* in this case it should wait until some value will be pushed to the stack.
13+
*/
14+
class SynchronizedBlockingStack<T> {
15+
private val list = mutableListOf<T>()
16+
private val lock = ReentrantLock()
17+
private val condition = lock.newCondition()
18+
19+
fun push(value: T) = lock.withLock {
20+
list.add(value)
21+
condition.signal()
22+
}
23+
24+
fun pop(): T = lock.withLock {
25+
while (list.isEmpty()) {
26+
condition.await()
1427
}
28+
list.removeLast()
29+
}
30+
31+
fun top(): T? = lock.withLock {
32+
list.lastOrNull()
33+
}
34+
35+
fun size(): Int = lock.withLock {
36+
list.size
1537
}
16-
threadPool.forEach { it.join() }
1738
}
1839

19-
fun main() {
20-
(1 .. 10).toList().parallelForEach(4) { i ->
21-
println("${i * i}")
40+
fun test1() {
41+
val stack = SynchronizedBlockingStack<Int>()
42+
thread {
43+
stack.push(1)
2244
}
45+
thread {
46+
stack.push(2)
47+
stack.push(3)
48+
}
49+
thread {
50+
val a = stack.pop()
51+
val b = stack.pop()
52+
val c = stack.pop()
53+
println("a=$a, b=$b, c=$c")
54+
// can print either:
55+
// a=3, b=2, a=1
56+
// a=1, b=3, c=2
57+
// a=3, b=1, a=2
58+
}
59+
}
60+
61+
fun test2() {
62+
val stack = SynchronizedBlockingStack<Int>()
63+
thread {
64+
println("push(1)")
65+
stack.push(1)
66+
}
67+
thread {
68+
val r = stack.pop()
69+
println("pop(): $r")
70+
}
71+
// can only print lines in the following sequence:
72+
// push(1), pop():1
73+
}
74+
75+
fun main() {
76+
test1()
77+
test2()
2378
}
Lines changed: 12 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,21 @@
11
package cub.concurrent.tasks
22

3-
import cub.concurrent.answers.SynchronizedBlockingStack
4-
import kotlin.concurrent.thread
5-
63
/*
7-
* Implement simple thread-safe blocking stack.
8-
* Use usual mutable list as an underlying storage.
4+
* Implement parallel version of forEach function, which applies given lambda to all elements of the collection.
5+
* Your implementation should distribute the work between threads dynamically.
6+
* That is you should not split the list into chunks of equal size and pass each chunk to a separate thread.
7+
* Instead, create a thread pool and in each thread handle elements one-by-one.
8+
*
9+
* Parameter `nThreads` specifies the number of threads that should be used to perform the job.
910
*
10-
* Methods can block the calling thread if they are executed concurrently with other methods.
11-
* Additionally, pop operation can also block the thread if the stack is empty ---
12-
* in this case it should wait until some value will be pushed to the stack.
1311
*/
14-
class SynchronizedBlockingStack<T> {
15-
private val list = mutableListOf<T>()
16-
17-
fun push(value: T) {
18-
TODO()
19-
}
20-
21-
fun pop(): T {
22-
TODO()
23-
}
24-
25-
fun top(): T? {
26-
TODO()
27-
}
28-
29-
fun size(): Int {
30-
TODO()
31-
}
32-
}
33-
34-
fun test1() {
35-
val stack = SynchronizedBlockingStack<Int>()
36-
thread {
37-
stack.push(1)
38-
}
39-
thread {
40-
stack.push(2)
41-
stack.push(3)
42-
}
43-
thread {
44-
val a = stack.pop()
45-
val b = stack.pop()
46-
val c = stack.pop()
47-
println("a=$a, b=$b, c=$c")
48-
// can print either:
49-
// a=3, b=2, a=1
50-
// a=1, b=3, c=2
51-
// a=3, b=1, a=2
52-
}
53-
}
54-
55-
fun test2() {
56-
val stack = SynchronizedBlockingStack<Int>()
57-
thread {
58-
println("push(1)")
59-
stack.push(1)
60-
}
61-
thread {
62-
val r = stack.pop()
63-
println("pop(): $r")
64-
}
65-
// can only print lines in the following sequence:
66-
// push(1)
67-
// pop():1
12+
fun<T> Collection<T>.parallelForEach(nThreads: Int, block: (T) -> Unit) {
13+
require(nThreads > 0) { "The number of threads must be > 0" }
14+
TODO()
6815
}
6916

7017
fun main() {
71-
test1()
72-
test2()
18+
(1 .. 10).toList().parallelForEach(4) { i ->
19+
println("${i * i}")
20+
}
7321
}
Lines changed: 64 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,73 @@
11
package cub.concurrent.tasks
22

3+
import cub.concurrent.answers.SynchronizedBlockingStack
4+
import kotlin.concurrent.thread
5+
36
/*
4-
* Implement parallel version of forEach function, which applies given lambda to all elements of the collection.
5-
* Your implementation should distribute the work between threads dynamically.
6-
* That is you should not split the list into chunks of equal size and pass each chunk to a separate thread.
7-
* Instead, create a thread pool and in each thread handle elements one-by-one.
8-
*
9-
* Parameter `nThreads` specifies the number of threads that should be used to perform the job.
7+
* Implement simple thread-safe blocking stack.
8+
* Use usual mutable list as an underlying storage.
109
*
10+
* Methods can block the calling thread if they are executed concurrently with other methods.
11+
* Additionally, pop operation can also block the thread if the stack is empty ---
12+
* in this case it should wait until some value will be pushed to the stack.
1113
*/
12-
fun<T> Collection<T>.parallelForEach(nThreads: Int, block: (T) -> Unit) {
13-
require(nThreads > 0) { "The number of threads must be > 0" }
14-
TODO()
14+
class SynchronizedBlockingStack<T> {
15+
private val list = mutableListOf<T>()
16+
17+
fun push(value: T) {
18+
TODO()
19+
}
20+
21+
fun pop(): T {
22+
TODO()
23+
}
24+
25+
fun top(): T? {
26+
TODO()
27+
}
28+
29+
fun size(): Int {
30+
TODO()
31+
}
1532
}
1633

17-
fun main() {
18-
(1 .. 10).toList().parallelForEach(4) { i ->
19-
println("${i * i}")
34+
fun test1() {
35+
val stack = SynchronizedBlockingStack<Int>()
36+
thread {
37+
stack.push(1)
38+
}
39+
thread {
40+
stack.push(2)
41+
stack.push(3)
42+
}
43+
thread {
44+
val a = stack.pop()
45+
val b = stack.pop()
46+
val c = stack.pop()
47+
println("a=$a, b=$b, c=$c")
48+
// can print either:
49+
// a=3, b=2, a=1
50+
// a=1, b=3, c=2
51+
// a=3, b=1, a=2
52+
}
53+
}
54+
55+
fun test2() {
56+
val stack = SynchronizedBlockingStack<Int>()
57+
thread {
58+
println("push(1)")
59+
stack.push(1)
60+
}
61+
thread {
62+
val r = stack.pop()
63+
println("pop(): $r")
2064
}
65+
// can only print lines in the following sequence:
66+
// push(1)
67+
// pop():1
68+
}
69+
70+
fun main() {
71+
test1()
72+
test2()
2173
}

0 commit comments

Comments
 (0)