Kotlinx.coroutines: SuspendCancellableCoroutine issue

Created on 15 Apr 2019  路  7Comments  路  Source: Kotlin/kotlinx.coroutines

hi

suspend fun ServerSocket.listening() = suspendCancellableCoroutine<Socket> {
    it.resume(accept())
    it.invokeOnCancellation { println("coroutine is canceling...."); close() }
}

fun main() = runBlocking {
    val job = launch {
        val server = ServerSocket(3000)
        server.listening()
    }
    delay(3000)
    job.cancel()
}

i expected after 3 sec coroutine is cancelled and throws an cancellationexception and server is close but not think happen and server still running after 3 sec

question

All 7 comments

accept if a blocking function. You cannot cancel it this way. Cancellation in coroutines in cooperative as explained here: https://kotlinlang.org/docs/reference/coroutines/cancellation-and-timeouts.html

Does it help?

thanks

val job = launch {
        val server = ServerSocket(3000)
        //server.listening()
        while(isActive) {
            server.accept()
        }
    }

if i understand carfully docs accept() deos not enable the check of coroutine cancellation (isActive) even if the job was canceled, so in this case (with methods blocking like accept()) how we can cancel coroutine and in wich case suspendCancellableCoroutine is useful ??

thanks

Yes. accept() is a blocking method and it does not support cancellation.

  1. any idea to fix that with coroutines ??
  2. how about use cases of suspendCancellableCoroutine

@halimpuckjava
What about something like this:

val SocketException.socketHasBeenClosed : Boolean get() = TODO()

suspend fun ServerSocket.listening() = suspendCancellableCoroutine<Socket> {
    it.invokeOnCancellation { try { close() } catch (e: Throwable){} }
    thread {
        try {
            it.resume(accept())
        } catch (e: SocketException) {
            if (e.socketHasBeenClosed) {
                it.cancel()
            }
            else {
                it.resumeWithException(e)
            }
        }
    }
}

(instead of thread { .... }, you may want to use a pool of threads instead, like from an ExecutorService)

If you want to make a non-blocking use of accept you don't need to create a thread yourself, just do this:

withContext(Dispatchers.IO) {
    socket.accept()
}

This way the caller is not going to be blocked. However, it will not be cancellable. Indeed, you can make it "cancellable" by closing socket on cancelled. There is not way to abort accept(), yet keep the socket open. You need asynchronous API (like java.nio) for that.

thanks,

Was this page helpful?
0 / 5 - 0 ratings