https://kotlinlang.org logo
#multiplatform
Title
# multiplatform
c

coletz

03/21/2020, 3:19 PM
Hi guys, how do you handle concurrent access to a map in a multiplatform project (jvm/native)? On the jvm side I would use a ConcurrentHashMap or something similar, but afaik there's nothing like that on k/n. Basically I am using this map for keeping reference to some lambda in order to call them when another variable is changed (basically a super simple listener). But I'm having obvious problems when removing a key while the underlying variable changes (which leads to a ConcurrentModificationException since I'm looping on the map) (ps: the problem is not removing a key INSIDE the loop, it's when another thread calls the remove method)
l

Luoqiaoyou

03/21/2020, 3:33 PM
kotlin/native concurrency model is very different. I use AtomicRef for now. And the other choice as i know is Stately, you can search in Github, it have a IsoMutableMap similar to ConcurrentHashMap. Otherwise, if u know better way, pls tell me.
🙏 1
c

coletz

03/21/2020, 3:59 PM
Thanks, going to try with stately's implementation. I used stately for other stuff, didn't know these iso collections
oh ok now I get why I didn't heard about stately-iso-collections. It's something pretty new, only included in the 1.0 alpha (I'm still using 0.9.5 since I need to use kotlin 1.3.61 and stately 1 is built for 1.3.70)
r

russhwolf

03/21/2020, 4:11 PM
yeah the iso-collections are brand new. You could also try the older collections implementation on 1.3.61 but they're much less performant
👍 1
c

coletz

03/21/2020, 4:16 PM
Well right now I don't really care about performance, I just want to get this working 😁 I'll need better performance in a couple months or so, and by that time I hope everything will be at least on kotlin 1.3.71
k

kpgalligan

03/21/2020, 5:24 PM
The older collections will work, but with 1.3.70 we decided to slowly deprecate them. As Russel mentions, the new ones are much faster and more flexible. https://dev.to/touchlab/kotlin-native-isolated-state-50l1
👍 1
c

coletz

03/21/2020, 5:46 PM
Yep, in fact it's working (at least on android, haven't tried on iOS). I started a project using your kamp kit, so I won't update libraries to 1.3.70 'til kamp kit will be updated 🙂
Hey @kpgalligan, as expected I'm having freeze problems on ios 😞 the crash happens in the put method in a SharedHashMap , is it caused by the fact that the object I'm putting inside is frozen (I am not really sure it's frozen, I'm trying to debug this issue but it a long task)?
The key is frozen. Since it's just a constant string I annotated it with @ThreadLocal, but it's still reported as frozen by isFrozen method. Am I missing something? I tried putting the string as a local final variable, as a companion object constant and as a top level constant, tried annotating them as thread local, but it's always frozen, no matter what I do 🤔
r

russhwolf

03/22/2020, 4:26 PM
Primitives and strings are always frozen. That shouldn't be causing you problems because they can't be mutated anyway. If you have an object giving you freeze issues, call
ensureNeverFrozen()
on it at initialization and you'll get a crash when it gets frozen telling you what freezes it
k

kpgalligan

03/22/2020, 4:30 PM
As Russell said, primitives and strings are always frozen. Also, anything, key or value, that goes into a SharedHashMap will be frozen when you put it in there. You are trying to share data between threads, which means it must be frozen. If you want to transfer mutable state, you’ll have to write something custom. We never transfer mutable state in production apps. It’s something you think you need, but you probably don’t. I have a blog post on doing it, but it’s just academic. I’ve found no situation where we absolutely need to pass mutable state around threads: https://dev.to/touchlab/kotlin-native-transferring-state-4n8i
It’s just very hard to do, and especially if you’re doing something like a map, the performance will be pretty bad.
c

coletz

03/22/2020, 4:30 PM
damn, totally forgot about the fact that primitives and strings are frozen. I have the ensureNeverFrozen but can't really understand the stacktrace. It's saying "*first blocker is my.app.id.provider.IdsProvider"* so I think that the frozen entity is IdsProvider, but checking "isFrozen" returns false 😐
k

kpgalligan

03/22/2020, 4:32 PM
If you call
ensureNeverFrozen
on
IdsProvider
, `isFrozen`will always return false. `ensureNeverFrozen`prevents it from freezing.
c

coletz

03/22/2020, 4:36 PM
Oh, got it now, many thanks. Yeah I need to avoid sharing state between threads for sure
Ok I think I'm a little bit lost. Now I'm just trying to test SharedHashMap behaviour, I have a super simple scenario:
Copy code
class Test {
    init {
        test1()
    }

    private val testMap1 = frozenHashMap<String, String>()
    private fun test1() {
        "test1.begin".log()
        testMap1["a"] = "hi1"
        "test1.end".log()
    }
}
executing this on iOS I get the first log printed (
Any?.log()
is just a println on iOS) then a
EXC_BAD_ACCESS
. So probably I'm not really understanding how to use the frozenHashMap on the iOS side I'm just instantiating a Test object in the AppDelegate's application method Edit: moving the test1() method call outside the init and calling it from iOS side seems to fix... I can't understand what is different in that, but seems like it's actually different Edit2: aaaaand my brain is completely fucked. Called again inside the init, now it's working. I have literally no idea about what is going on, probably something was cached and idk, just trying to justify something that is no-sense to me. Thanks everyone anyway for your support guys
k

kpgalligan

03/22/2020, 6:18 PM
Can you post the current
Test
code? My only guess on the previous was that `testMap1`wasn’t properly initialized when init was called
c

coletz

03/22/2020, 6:23 PM
Damn you are totally right. While poking around I moved testMap1 before the init block... I think I need to take a break, I'm doing stupid errors. Thanks again Kevin and sorry for the wasted time 🙏
k

kpgalligan

03/22/2020, 6:36 PM
Init order is confusing. I've hit that more than once
15 Views