Skip to content

CoroutineDispatcher.dispatch ignores the context parameter. #3354

@bc-lee

Description

@bc-lee

According to the link and source, CoroutineDispatcher.dispatch has the following behavior:

Dispatches execution of a runnable [block] onto another thread in the given [context]

But from what I've tested, CoroutineDispatcher.dispatch ignores the context parameter.

For example,

Click to toggle contents of `code`
@OptIn(ExperimentalCoroutinesApi::class)
class SerialTaskQueue {
    private class CoroutineQueueDepthContext(val taskQueue: SerialTaskQueue) :
        ThreadContextElement<Unit> {
        companion object Key : CoroutineContext.Key<CoroutineQueueDepthContext>

        override val key: CoroutineContext.Key<CoroutineQueueDepthContext>
            get() = Key

        // this is invoked before coroutine is resumed on current thread
        override fun updateThreadContext(context: CoroutineContext) {
            taskQueue.queueDepth.set(1)
        }

        // this is invoked after coroutine has suspended on current thread
        override fun restoreThreadContext(context: CoroutineContext, oldState: Unit) {
            taskQueue.queueDepth.set(0)
        }
    }

    private val dispatcher = Dispatchers.IO.limitedParallelism(1)

    private var queueDepth = ThreadLocal<Int>()

    fun post(action: () -> Unit) {
        dispatcher.dispatch(CoroutineQueueDepthContext(this), action)
    }

    fun post2(action: () -> Unit) {
        CoroutineScope(EmptyCoroutineContext).launch(
                dispatcher + CoroutineQueueDepthContext(this)) { action() }
    }

    fun isCurrent(): Boolean {
        return (queueDepth.get() ?: 0) > 0
    }
}

fun main() {
    val taskQueue = SerialTaskQueue()
    val latch = CountDownLatch(2)
    taskQueue.post {
        println("taskQueue.post isCurrent: ${taskQueue.isCurrent()}")
        latch.countDown()
    }
    taskQueue.post2 {
        println("taskQueue.post2 isCurrent: ${taskQueue.isCurrent()}")
        latch.countDown()
    }
    latch.await()
}

The code above will return something like this:

taskQueue.post isCurrent: false
taskQueue.post2 isCurrent: true

However, according to the documentation, both method calls should output true.

The above tests used org.jetbrains.kotlin:kotlin-stdlib-common:1.7.0 and org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.3 in JVM.

Metadata

Metadata

Assignees

Labels

docsKDoc and API reference

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions