EFC
EFC

Reputation: 110

Kotlin coroutines Mutex owner usage

What is the expected usage of owner in a kotlinx.coroutines.sync.Mutex?

From what I understand a Mutex.withLock will make any calling coroutine after the first (witch locked the mutex), await until it is unlocked, and then hold the lock themselves.

So, what could be causing the following error?

2019-12-06 15:29:30.508 6380-6840/com.[...] E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-3
    Process: com.[...], PID: 6380
    java.lang.IllegalStateException: Already locked by [...].source.local.configuration.ConfigurationCacheSourceImpl@c86499c
        at kotlinx.coroutines.sync.MutexImpl.lockSuspend(Mutex.kt:208)
        at kotlinx.coroutines.sync.MutexImpl.lock(Mutex.kt:187)
        at com.[...].source.local.cache.CacheSource.invoke$suspendImpl(CacheSource.kt:52)
        at com.[...].source.local.cache.CacheSource.invoke(Unknown Source:0)
        at com.[...].source.local.cache.ICacheSource$DefaultImpls.invoke$default(CacheSource.kt:10)
        at com.[...].repository.ConfigurationRepositoryImpl.getStuff(ConfigurationRepository.kt:14)
        at com.[...].interactor.ConfigurationInteractorImpl.getStuff(CongifurationInteractor.kt:16)
        at com.[...]
        at com.[...]
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:241)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:740)

Note, that I am always using the same owneron its withLock calls, as per:

abstract class CacheSource<T>(
    private val cacheMutex = Mutex()

    override suspend operator fun invoke(
        [...]
    ): T = cacheMutex.withLock(this) {
        [...]
    }
}

And as per docs:

owner - Optional owner token for debugging. When owner is specified (non-null value) and this mutex is already locked with the same token (same identity), this function throws IllegalStateException.

Upvotes: 2

Views: 7860

Answers (2)

Muse
Muse

Reputation: 460

Use Mutex.holdsLock check owner is already locked, you can't lock the same owner while owner is locked.

Upvotes: 0

Roman  Elizarov
Roman Elizarov

Reputation: 28658

The purpose of the owner in Mutex is explained in the documentation of the corresponding parameters. Coroutine mutexes are non-reentrant and so it is relatively easy to get into a "deadlock" while trying to reacquire the lock that is already acquired. Also, while implementing complex locking patterns like hand-over locking it might be easy to mess up and release a lock you were not supposed to hold.

So owner is an optional aid for debugging. When owner is specified (non-null value) and the mutex is already locked with the same owner (same identity), then lock function throws IllegalStateException. Similarly, attempting to unlock with a wrong owner throws IllegalStateException.

See the documentation on lock and unlock functions for details:

Upvotes: 3

Related Questions