I have a class that has several suspend fun method...
# coroutines
r
I have a class that has several suspend fun methods that need to be exclusive. I looked at using
Mutex.withLock
but it's not reentrant. Is there a better way to achieve this?
s
Can you offload the work that needs to be done in a 'safe' way onto a single-thread dispatcher? You could then call withContext(mySingleThreadedDispatcher) and make it 'safe' that way.
r
I don't think that would work either because a single thread dispatcher could switch between exclusive blocks
s
True, it would make it only 'thread' safe; things could still happen asynchronously.
r
Here is what I've come up with but I think there should be a nicer way?
Copy code
private suspend fun <R> reentrantLock(block: suspend () -> R) = withContext(<http://Dispatchers.IO|Dispatchers.IO>) {
        synchronized(this@MyClass) {
            runBlocking {
                block()
            }
        }
    }
I have no idea if this works
s
If it is a truly critical/exclusive block, the
block
lambda param should not be
suspend
...
r
If it is a suspend, it should wait for the last method to complete before entering
That is a valid usecase IMO
That is literally what
synchronized
does
y
I've seen a trick before by passing into the coroutine context a marker to say that the mutex is locked by this coroutine. Lemme see if I can find it
https://elizarov.medium.com/phantom-of-the-coroutine-afc63b03a131 Expand the last example in the above article!
👍 1
r
I thought about making the
withReentrantLock
before reading the article but thought it was too much work and just refactored it to not require it. In the comments Roman says just don't writing code that need a reentrant lock but sometimes it's unavoidable.