<@U3SK5B492> I'm doing some theory crafting here. ...
# kotlin-native
s
@olonho I'm doing some theory crafting here. If I were to store an
NSMutableArray
cast to a
List<>
in the following object, would this have any problems being frozen shared between threads safely in Kotlin/native?
Copy code
internal actual class LockedRef<T> actual constructor(
    private val ref: T
) {
    internal val lock = NSRecursiveLock()

    actual inline fun <R> accessAtomically(block: (T) -> R): R {
        lock.lock()
        try {
            memScoped {
                return block(ref)
            }
        } finally {
            lock.unlock()
        }
    }
}
Example Usage:
Copy code
internal class Test() {
    val ref = LockedRef<List<Any>>(NSMutableArray() as List<Any>)
    
    init {
        freeze()
    }
}
s
This should work properly. Btw, your
memScoped
doesn’t seem to have any effect.
s
I put in in there to try and circumvent a race condition I was told about.
I was told that the reference counting to my locked reference will actually decrement after the lock is unlocked, thus allowing a race condition. I tried to circumvent that with
memScoped
. Do you still think I can get rid of
memScoped
?
k
I'm actually doing some mem tests now, so I'll see if I can cause the race condition
I did get that to happen months ago, but the situation may be different now...
s
memScoped
is completely unrelated to any reference counting.
k
I was saying that leaving the function will trigger a decrement, and if the 'ref' isn't frozen, it'll be a race condition (potentially)
decrement of ref count
I could be wrong, but it looks like there's a new feature that checks reference ownership on non-frozen objects, which will prevent this from working regardless (although I may be reading Memory.cpp wrong)
Fails with...
Uncaught Kotlin exception: kotlin.native.IncorrectDereferenceException: illegal attempt to access non-shared sample.SampleTestsIOS.LockedRef@da400538 from other thread at 0 test.kexe 0x000000010ad188e6 kfun:kotlin.Exception.<init>(kotlin.String?)kotlin.Exception + 70
That's good. Earlier versions of K/N would let you share non-frozen data and cause a race condition. Looking at git, the relevant code in Memory.cpp is pretty recent
s
k
Ah, OK
s
Objective-C class instances are opaque for Kotlin object freezing.
k
OK. I think I'm lost on how you'll be able to put a kotlin, non-frozen piece of state into the locked ref, which is the goal. Obviously Objc interop isn't affected by freezing, but now you need to add a value into that mutable array that is not frozen
IN the original post, internal actual class LockedRef<T> actual constructor( private val ref: T
'ref' isn't frozen and is intended to be passed around to multiple threads with a lock around it
Yes?
We're having dual conversations, public and private
The goal, ultimately, is to have non-frozen data shared, backed by a lock
If that is the goal, the next step is to put data into that array inside of "LockedRef". However, whatever gets put in there, if its a kotlin object, would not be frozen.
o
as long as it is detached, just use lockless
AtomicReference<DetachedObjectGraph<T>>
k
I agree
Scott doesn't, which is how we got here 🙂
o
so he just wants to circumvent K/N safety mechanisms 🙂?
k
Yes
o
then I would recommend to store data in C/Objective-C structure
k
I'm relaying my same attempts in May/June, which I've ultimately abandoned
and just access the data from shared C memory
shared mutable Kotlin objects are not supported
k
Yes, that ^
s
@olonho So it's not safe / won't work?
o
it does not work and is not safe
s
Can you explain what will go wrong, for my own learning?
o
memory manager will not be able to collect cyclic garbage, race conditions of all kinds may happen
s
Alright, I'll swap it to use atomic
k
And detached, if not freezing
s
How would I ensure it only gets attached to 1 thread at a time?
k
Lock
As you're doing now
You'll need to attach and detach in that single operation each time (which is why I got excited then less excited about detach)
s
meh. I'll just go immutable atomic
k
DetachedObjectGraph is disposable. You can't "detach again" after attaching, so you need the atomic ref to change the instance