How to suspend a coroutine at a specific point

痴心易碎 提交于 2019-12-10 10:16:47

问题


I am at loss with the following problem.

I have the following code:

val parentJob: Job = Job()

launch(parent = parentJob) {
    while (true)
    {
        if (!parentJob.isCompleted)
        {
            // I want to control suspension here
            println("Resumed")
        }
    }
}

I would like to be able to control, somehow akin to a semaphore, when should the coroutine suspend and when to resume exactly in the commented part of the snippet

I know there's suspendCancellableCoroutine but I am unsure how to use it or if it is appropriate here

How can this be achieved or are there any tutorials about this?


回答1:


It would be more helpful to think about coroutines in terms of callbacks and continuations, not threads and semaphores.

Internally, when the coroutine is suspended, the entire chain of suspend fun calls returns with a special internal object, COROUTINE_SUSPENDED. So the whole execution of a coroutine is just a function call during which a callback object is being built up. This callback is the continuation and when you call it, execution resumes from the place which returned the special COROUTINE_SUSPENDED object.

Kotlin runs the block you pass to suspendCancellableCoroutine with the continuation object as the parameter. So you should save this object and make it available to the code outside the coroutine.

Here's some code that may help your understanding. Note there's no need to create a separate parent job if you want to cancel the coroutine. You can just cancel the Job instance that launch returns and the coroutine will not resume after suspension.

import kotlin.coroutines.*
import kotlinx.coroutines.*

var continuation: Continuation<String>? = null

fun main(args: Array<String>) {
    val job = GlobalScope.launch(Dispatchers.Unconfined) {
        while (true) {
            println(suspendHere())
        }
    }

    continuation!!.resume("Resumed first time")
    continuation!!.resume("Resumed second time")
    job.cancel()
    continuation!!.resume("This shouldn't print")
}

suspend fun suspendHere() = suspendCancellableCoroutine<String> {
    continuation = it
}

If you still need an explicit check (because there aren't enough suspension points on the execution path), you can just use the isActive property which is available directly to the block:

while (isActive) ...


来源:https://stackoverflow.com/questions/51566006/how-to-suspend-a-coroutine-at-a-specific-point

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!