Reputation: 110
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 owner
on 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
Reputation: 460
Use Mutex.holdsLock check owner is already locked, you can't lock the same owner while owner is locked.
Upvotes: 0
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