I have a use case where I have two functions withi...
# coroutines
s
I have a use case where I have two functions within the same class: first performs sequential periodic updates on the shared mutable state with given fixed delay and is invoked only once, and second, which does some processing of the data and is expected to be called concurrently. When there is active processing taking place in
functionOne
, I would like to indicate that and make any invocations of
functionTwo
wait before this processing is done. So basically, I would like
funtionOne
to be able to acquire some lock for the processing time and
functionTwo
to wait until this lock is freed before doing anything. I had two working approaches to it: First, more straight forward uses mutex:
Copy code
private val mutex = Mutex()
private val fixedDelay = 2.seconds

suspend fun functionOne() {
    while (coroutineContext.isActive) {
        delay(fixedDelay)
        mutex.withLock {
            [actual processing]
        }
    }
}

suspend fun functionTwo() {
    mutex.withLock { }
    [actual processing]
}
I'm using empty
withLock
block within
functionTwo
just to wait until lock is freed in case
functionOne
is actively processing. Ideally, I wouldn't want
functionTwo
to acquire any kind of new lock at all, as multiple parallel invocations of it are expected, but there is no
awaitUntilUnlocked
or similar API for Mutex. The Second approach I thought about is by using MutableStateFlow.
Copy code
private val processingStateFlow = MutableStateFlow(ProcessingLockState.FREE)
private val fixedDelay = 2.seconds

suspend fun functionOne() {
    while (coroutineContext.isActive) {
        delay(fixedDelay)
        processingStateFlow.value = ProcessingLockState.LOCKED
        try {
            [actual processing]
        } catch (ex: Exception) {
            [exception handling]
        } finally {
            processingStateFlow.value = ProcessingLockState.FREE
        }
    }
}

suspend fun functionTwo() {
    processingStateFlow.first { it == ProcessingLockState.FREE }
    [actual processing]
}

private enum class ProcessingLockState {
    FREE, LOCKED
}
This approach also works for me, and even better,
functionTwo
does not affect the lock state at all, but to me, it feels a little like I'm rewriting the API that may already be there. What do you think? Can you advise how you would handle such situations? ----------------------- TLDR: I want one function to non-blockingly wait until other function finishes processing, only if it is processing at the time. So that first function can acquire lock and second wait have to wait for it to be released without affecting lock state at