Synchronized and withContext
Asked Answered
F

1

6

I have the following class:

class SdkWrapper(private val sdk: Sdk) {

    private var inited = false

    suspend fun doSomething() = withContext(Dispatchers.IO) {
        if (inited.not()) init()
        useSdk()
    }
        
    private fun init() {
        // takes a long time
        sdk.init()
        inited = true
    }

    // has to be done asynchronously
    // sdk.init() has to have been called before using this
    private fun useSdk() {

    }

}

class Sdk {
    // must only be done once
    fun init() {}
}

Before I can do useSdk(), I must call sdk.init(), but sdk.init() must only be called once, not more.

With my current solution, if doSomething is called twice quickly (the second time happening while sdk.init() still running), I would call sdk.init() twice, because inited: Boolean is still false.

If I move the assignment of inited up like:

private fun init() {
    inited = true
    sdk.init()
}

and doSomething() is called twice rapidly, the second call would use the sdk before its' init() has been done.

I tried to solve this with:

suspend fun doSomething() = synchronized(this){
    withContext(Dispatchers.IO) {
        if (inited.not()) init()
        useSdk()
    }
}

but receive an error in IntelliJ:

the withContext suspension point is inside a critical section

I assume that synchronized wouldn't work here anyway, because we move off the main thread and doSomething() is completed while the withContext block is still running?

How can I solve the problem at hand which basically is: doSomething() should only run once at a time?

Fleming answered 9/10, 2020 at 9:9 Comment(0)
D
20

Instead of synchronized {...} you can use a Mutex:

class SdkWrapper(private val sdk: Sdk) {

    ...

    private val mutex = Mutex()

    suspend fun doSomething() = mutex.withLock {
        withContext(Dispatchers.IO) {
            if (inited.not()) init()
            useSdk()
        }
    }

    ...

}

You can take a look at the official documentation about Coroutines and mutual exclusion here.

Donell answered 9/10, 2020 at 10:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.