首页 > 解决方案 > 未捕获的 Kotlin 异常:kotlin.native.IncorrectDereferenceException:非法尝试访问非共享

问题描述

我尝试使用 Kotlin MPP(Multiplatform) 在 Android 和 iOS 之间开发共享库。但我面临关于iOS中线程的问题。对于我在 iOS 中的应用程序,我在主线程中建立了对象,但它可能会在另一个线程中调用该函数并抛出此异常,如下所示:

Uncaught Kotlin exception: kotlin.native.IncorrectDereferenceException: illegal attempt to access non-shared example.api.DrivingBehaviorDetector@397cba8 from other thread
        at 0   DrivingBehaviorDetector             0x00000001037619d7 kfun:kotlin.Throwable.<init>(kotlin.String?)kotlin.Throwable + 87
        at 1   DrivingBehaviorDetector             0x000000010375bca5 kfun:kotlin.Exception.<init>(kotlin.String?)kotlin.Exception + 85
        at 2   DrivingBehaviorDetector             0x000000010375b9a5 kfun:kotlin.RuntimeException.<init>(kotlin.String?)kotlin.RuntimeException + 85
        at 3   DrivingBehaviorDetector             0x0000000103781395 kfun:kotlin.native.IncorrectDereferenceException.<init>(kotlin.String)kotlin.native.IncorrectDereferenceException + 85
        at 4   DrivingBehaviorDetector             0x0000000103782568 ThrowIllegalObjectSharingException + 744
        at 5   DrivingBehaviorDetector             0x00000001037d72bc _ZNK27BackRefFromAssociatedObject19ensureRefAccessibleEv + 76
        at 6   DrivingBehaviorDetector             0x00000001037c97c3 -[KotlinBase toKotlin:] + 35
        at 7   DrivingBehaviorDetector             0x00000001037e3ef1 Kotlin_ObjCExport_refFromObjC + 65
        at 8   DrivingBehaviorDetector             0x00000001037c4e37 objc2kotlin.125 + 167
        at 9   Test                                0x000000010340224d $sIeg_IeyB_TR + 45 (/Users/james/Documents/Projects/go/TestMPPforiOS/<compiler-generated>:<unknown>)
        at 10  libdispatch.dylib                   0x0000000103959dd4 _dispatch_call_block_and_release + 12
        at 11  libdispatch.dylib                   0x000000010395ad48 _dispatch_client_callout + 8
        at 12  libdispatch.dylib                   0x000000010396c460 _dispatch_root_queue_drain + 819
        at 13  libdispatch.dylib                   0x000000010396cb96 _dispatch_worker_thread2 + 132
        at 14  libsystem_pthread.dylib             0x00007fff5245f6b3 _pthread_wqthread + 583
        at 15  libsystem_pthread.dylib             0x00007fff5245f3fd start_wqthread + 13
(lldb) 

我在这些文章中调查了解决方案:

Kotlin/Native中的不变性:Kotlin/Native 中的不变性

K/N 的协程和不变性:K/N 的协程和不变性

我的 API(共享库)的入口如下:

class DrivingBehaviorDetector (
    private var gravity:Vector?,
    private var front:Vector?,
    onGravityOrFrontChanged: ((newGravity: Vector?, newFront: Vector?, timestamp: Long) -> Unit)?,
    onDrivingEventDetected: ((event: DrivingEvent) -> Unit)?
) {

    private val lowPassFilter = LowPassFilter()
    private val accProcessor = AccProcessor(gravity, front, onGravityOrFrontChanged, onDrivingEventDetected)

    init {
        gravity = gravity?.toCoreUnit()
        front = front?.toCoreUnit()
    }

    fun addData(data:Acceleration) {
        val rawAcc = data.toCoreUnit()
        val filterAcc = lowPassFilter.lowPass(rawAcc)
        accProcessor.addData(filterAcc)
    }

    fun addData(data:List<Acceleration>) {
        for(acc in data) {
            addData(acc)
        }
    }
}

我们可以注意到 API 非常简单,只需输入大量数据并回调一些计算的结果。但是在iOS中抛出异常和代码如下:

let drivingBehaviorDetector = DrivingBehaviorDetector(gravity: nil, front: nil, onGravityOrFrontChanged: { (newGravity, newFront, timestamp) in
    print("newGravity = \(newGravity)")
    print("newFront = \(newFront)")
}) { (event) in
    print("event = \(event.description())")
}

let acc1 = Acceleration(vector: Vector(x: 0, y: 0, z: 0))
let acc2 = Acceleration(vector: Vector(x: 0, y: 100, z: 0))

drivingBehaviorDetector.addData(data: acc1)

DispatchQueue.global(qos: .background).async {
    drivingBehaviorDetector.addData(data: acc2)
}

我能想象的唯一一个解决方案是强制在同一个线程中使用 API,但这似乎有点奇怪。是否可以通过修改共享库来解决这个问题。因为 mu 的使用很简单,只有一个“DrivingBehaviorDetector”,但它可以在不同的线程中调用“addData”函数。谢谢回答。

标签: swiftkotlinkotlin-multiplatformkotlin-native

解决方案


对于 Kotlin/Native,必须明确定义正确的并发行为,以避免竞争。在这种特殊情况下,有几种选择:


推荐阅读