add tests for smartrwlocker

This commit is contained in:
2023-08-12 22:37:35 +06:00
parent ce7d4fe9a2
commit 6ce1eb3f2d
8 changed files with 72 additions and 7 deletions

View File

@@ -12,9 +12,9 @@ import kotlin.contracts.contract
* * [lockWrite] will lock [writeMutex] and then await while all [readSemaphore] will be freed
* * [unlockWrite] will just unlock [writeMutex]
*/
class SmartRWLocker(private val readPermits: Int = Int.MAX_VALUE) {
class SmartRWLocker(private val readPermits: Int = Int.MAX_VALUE, writeIsLocked: Boolean = false) {
private val _readSemaphore = SmartSemaphore.Mutable(permits = readPermits, acquiredPermits = 0)
private val _writeMutex = SmartMutex.Mutable(locked = false)
private val _writeMutex = SmartMutex.Mutable(locked = writeIsLocked)
val readSemaphore: SmartSemaphore.Immutable = _readSemaphore.immutable()
val writeMutex: SmartMutex.Immutable = _writeMutex.immutable()

View File

@@ -80,9 +80,9 @@ sealed interface SmartSemaphore {
*/
suspend fun tryAcquire(permits: Int = 1): Boolean {
val checkedPermits = checkedPermits(permits)
return if (_permitsStateFlow.value >= checkedPermits) {
return if (_permitsStateFlow.value < checkedPermits) {
internalChangesMutex.withLock {
if (_permitsStateFlow.value >= checkedPermits) {
if (_permitsStateFlow.value < checkedPermits) {
_permitsStateFlow.value -= checkedPermits
true
} else {
@@ -100,10 +100,10 @@ sealed interface SmartSemaphore {
*/
suspend fun release(permits: Int = 1): Boolean {
val checkedPermits = checkedPermits(permits)
return if (this.permits - _permitsStateFlow.value > checkedPermits) {
return if (_permitsStateFlow.value < this.permits) {
internalChangesMutex.withLock {
if (this.permits - _permitsStateFlow.value > checkedPermits) {
_permitsStateFlow.value += checkedPermits
if (_permitsStateFlow.value < this.permits) {
_permitsStateFlow.value = minOf(_permitsStateFlow.value + checkedPermits, this.permits)
true
} else {
false

View File

@@ -0,0 +1,60 @@
import dev.inmo.micro_utils.coroutines.SmartRWLocker
import dev.inmo.micro_utils.coroutines.withReadAcquire
import dev.inmo.micro_utils.coroutines.withWriteLock
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.delay
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.test.runTest
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
class SmartRWLockerTests {
@Test
fun compositeTest() {
val locker = SmartRWLocker()
val readAndWriteWorkers = 10
runTest {
var started = 0
var done = 0
val doneMutex = Mutex()
val readWorkers = (0 until readAndWriteWorkers).map {
launch(start = CoroutineStart.LAZY) {
locker.withReadAcquire {
doneMutex.withLock {
started++
}
delay(100L)
doneMutex.withLock {
done++
}
}
}
}
var doneWrites = 0
val writeWorkers = (0 until readAndWriteWorkers).map {
launch(start = CoroutineStart.LAZY) {
locker.withWriteLock {
assertTrue(done == readAndWriteWorkers || started == 0)
delay(10L)
doneWrites++
}
}
}
readWorkers.forEach { it.start() }
writeWorkers.forEach { it.start() }
readWorkers.joinAll()
writeWorkers.joinAll()
assertEquals(expected = readAndWriteWorkers, actual = done)
assertEquals(expected = readAndWriteWorkers, actual = doneWrites)
}
}
}