Intensive Course on Concurrent Programming
Day 1
Coarse-grained bank
In src/day1/CoarseGrainedBank.kt
,
make the sequential bank implementation thread-safe.
Please follow the coarse-grained locking scheme to make synchronization efficient.
For that, you need to use a single lock to protect all bank operations.
To test your solution, please run:
./gradlew test --tests CoarseGrainedBankTest
on Linux or MacOSgradlew test --tests CoarseGrainedBankTest
on Windows
Fine-grained bank
In src/day1/FineGrainedBank.kt
,
make the sequential bank implementation thread-safe.
Please follow the fine-grained locking scheme to make synchronization efficient.
For that, you need to use per-account locks, thus, ensuring natural parallelism
when accessing different accounts. The totalAmount()
function should acquire
all the locks to get a consistent snapshot, while transfer(..)
should acquire
the corresponding account locks.
To test your solution, please run:
./gradlew test --tests FineGrainedBankTest
on Linux or MacOSgradlew test --tests FineGrainedBankTest
on Windows
Treiber stack
In src/day1/TreiberStack.kt
,
implement the classic Treiber stack algorithm.
To test your solution, please run:
./gradlew test --tests TreiberStackTest
on Linux or MacOSgradlew test --tests TreiberStackTest
on Windows
Treiber stack with elimination
In src/day1/TreiberStackWithElimination.kt
,
implement the classic Treiber stack algorithm with the elimination technique.
To test your solution, please run:
./gradlew test --tests TreiberStackWithEliminationTest
on Linux or MacOSgradlew test --tests TreiberStackWithEliminationTest
on Windows
Michael-Scott queue
In src/day1/MSQueue.kt
,
implement the Michael-Scott queue algorithm.
You might also be interested in the original paper.
To test your solution, please run:
./gradlew test --tests MSQueueTest
on Linux or MacOSgradlew test --tests MSQueueTest
on Windows
Day 2
FAA-based queue: simplified
In src/day2/FAABasedQueueSimplified.kt
,
implement a concurrent queue that leverages the Fetch-and-Add
synchronization primitive.
The high-level design of this queue bases on a conceptually infinite array for storing elements and manipulates
enqIdx
and deqIdx
counters, which reference the next working cells in the infinite array for enqueue(..)
and dequeue()
operations.
In this task, use a big plain array as the infinite array implementation.
To test your solution, please run:
./gradlew test --tests FAABasedQueueSimplifiedTest
on Linux or MacOSgradlew test --tests FAABasedQueueSimplifiedTest
on Windows
FAA-based queue
In src/day2/FAABasedQueue.kt
,
implement a concurrent queue that leverages the Fetch-and-Add
synchronization primitive.
The high-level design of this queue bases on a conceptually infinite array for storing elements and manipulates
enqIdx
and deqIdx
counters, which reference the next working cells in the infinite array for enqueue(..)
and dequeue()
operations.
The infinite array implementation should be simulated via a linked list of fixed-size segments. The overall algorithm should be obstruction-free or lock-free.
To test your solution, please run:
./gradlew test --tests FAABasedQueueTest
on Linux or MacOSgradlew test --tests FAABasedQueueTest
on Windows
Logical removals in Michael-Scott queue
In src/day2/MSQueueWithOnlyLogicalRemove.kt
,
implement a Michael-Scott queue with an additional remove(element)
operation.
The implementation should remove elements only logically, keeping the corresponding nodes
in the linked list physically, but marking them as removed.
To test your solution, please run:
./gradlew test --tests MSQueueWithOnlyLogicalRemoveTest
on Linux or MacOSgradlew test --tests MSQueueWithOnlyLogicalRemoveTest
on Windows
Linear-time non-parallel removals in Michael-Scott queue
In src/day2/MSQueueWithLinearTimeNonParallelRemove.kt
,
implement a Michael-Scott queue with an additional remove(element)
operation.
The implementation should find the first node that contains the specified element
in linear time and then remove this node also in linear time.
Note that in this task remove(..)
operations are never called in parallel, which simplifies the implementation.
To test your solution, please run:
./gradlew test --tests MSQueueWithLinearTimeNonParallelRemoveTest
on Linux or MacOSgradlew test --tests MSQueueWithLinearTimeNonParallelRemoveTest
on Windows
Linear-time removals in Michael-Scott queue
In src/day2/MSQueueWithLinearTimeRemove.kt
,
implement a Michael-Scott queue with an additional remove(element)
operation.
The implementation should find the first node that contains the specified element
in linear time and then remove this node also in linear time.
To test your solution, please run:
./gradlew test --tests MSQueueWithLinearTimeRemoveTest
on Linux or MacOSgradlew test --tests MSQueueWithLinearTimeRemoveTest
on Windows
Constant-time removals in Michael-Scott queue
In src/day2/MSQueueWithConstantTimeRemove.kt
,
implement a Michael-Scott queue with an additional remove(element)
operation.
The implementation should find the first node that contains the specified element
in linear time, but remove this node in constant time.
./gradlew test --tests MSQueueWithConstantTimeRemoveTest
on Linux or MacOSgradlew test --tests MSQueueWithConstantTimeRemoveTest
on Windows
Day 3
CAS2: Single-Writer
In src/day3/AtomicArrayWithCAS2SingleWriter.kt
,
implement the cas2(..)
and get(..)
operations.
In this data task, CAS2(..)
can be called only in one thread,
so concurrent CAS2(..)
invocations are forbidden.
To test your solution, please run:
./gradlew test --tests AtomicArrayWithCAS2SingleWriterTest
on Linux or MacOSgradlew test --tests AtomicArrayWithCAS2SingleWriterTest
on Windows
CAS2: Simplified
In src/day3/AtomicArrayWithCAS2Simplified.kt
,
implement the cas2(..)
operation. In this data task, all successful updates
install unique values in the array cells.
To test your solution, please run:
./gradlew test --tests AtomicArrayWithCAS2SimplifiedTest
on Linux or MacOSgradlew test --tests AtomicArrayWithCAS2SimplifiedTest
on Windows
CAS2: With Implemented DCSS
In src/day3/AtomicArrayWithCAS2.kt
,
implement the cas2(..)
operation.
Unlike in the "CAS2: Simplified" task, updates are no longer unique.
This can lead to the ABA problem. To solve it, please use
the already implemented Double-Compare-Single-Set operation when installing CAS2 descriptors.
To test your solution, please run:
./gradlew test --tests AtomicArrayWithCAS2Test
on Linux or MacOSgradlew test --tests AtomicArrayWithCAS2Test
on Windows
CAS2
In src/day3/AtomicArrayWithCAS2.kt
,
implement the cas2(..)
operation.
Unlike in the "CAS2: Simplified" task, updates are no longer unique.
This can lead to the ABA problem. To solve it, please use
the Double-Compare-Single-Set operation when installing CAS2 descriptors.
In this task, you need to implement DCSS via descriptors.
To test your solution, please run:
./gradlew test --tests AtomicArrayWithCAS2Test
on Linux or MacOSgradlew test --tests AtomicArrayWithCAS2Test
on Windows