Michael Strasser
05/04/2023, 7:11 AMMutableStateFlow
.
Because the value
property is thread-safe, does it make sense to use MutableStateFlow
as a multiplatform, thread-safe delegate, like this?
class ThreadSafeMap<K, V>(
vararg pairs: Pair<K, V>
) : MutableMap<K, V> by MutableStateFlow(
mutableMapOf(*pairs)
).value
Nicklas Jensen
05/04/2023, 7:47 AMMutableMap
thread-safe since you're effectively exposing it to the caller as-is (through delegation). To make it thread-safe you'd have to implement the MutableMap
interface yourself while making sure every operation you perform is thread-safe.Michael Strasser
05/04/2023, 9:52 AMMutableStateFlow
object when using delegation. (The delegate is the MutableMap
it contains.)
Is there a way to get access to the delegate object within the delegating class?Michael Strasser
05/04/2023, 10:04 AMMutableMap
implementation without delegation:
class ThreadSafeMap<K, V>(
vararg pairs: Pair<K, V>
): MutableMap<K, V> {
private val _mapFlow = MutableStateFlow(mutableMapOf(*pairs))
// Read-only property
override val keys: MutableSet<K>
get() = _mapFlow.value.entries
// Function without a return value
override fun clear(): Unit = _mapFlow.update { it.apply { clear() } }
// Function that returns a value
override fun remove(key: K): V? {
var previousValue: V? = null
// The lambda provided to MutableStateFlow.update()
// needs to return the mutable map
_mapFlow.update { it.apply { previousValue = remove(key) } }
return previousValue
}
// etc.
}
I think this would work.Nicklas Jensen
05/04/2023, 10:57 AMupdate
function of MutableStateFlow
is atomic, but in reality, as long as you're storing and mutating a MutableMap
in your MutableStateFlow
you will find it hard to make it "thread-safe". A "simple" version of a thread-safe MutableMap
could be implemented using locks from atomic-fu, or by storing an immutable Map
in your MutableStateFlow
and just updating that in your update
function. Doing so you may as well use atomic<T>
from atomic-fu, e.g. like in this snippet.Nicklas Jensen
05/04/2023, 10:58 AMMap
though? If you're only modifying it from a single thread, then you can just use an immutable Map
stored in an AtomicRef
and read it from as many threads as you like. You only need the "mutation thread safety" if you're actually mutating the Map
from several threadsMichael Strasser
05/04/2023, 11:06 AMConcurrentHashMap
.
But I want to make Klogging multiplatform so I need a different solution. I had looked a bit at atomic-fu but wasn’t sure if was still experimental.Nicklas Jensen
05/04/2023, 11:11 AMMutableStateFlow
😄Nicklas Jensen
05/04/2023, 11:12 AMfun get(key: K): V? = map.value.get(key)
Because the underlying Map
is immutable (I have updated my snippet)