Djuro
02/08/2024, 9:45 AMrunInterruptible
I am using it to make a blocking IO call cancellable
Here is the code
suspend fun foo () {
withContext(ioDispatcher){
runInterruptible{
print("reading")
inputStream.read(buffer)
print("finish reading")
}
}
}
val job = scope.launch{foo()}
delay(200)
job.cancelAndJoin()
What happens is that as output I get
reading
finish reading
Shouldn't it be just
reading
Is this the expected behaviour?Joffrey
02/08/2024, 9:56 AMInputStream reads are not interruptible, so you can't use runInterruptible like you're trying to do.Joffrey
02/08/2024, 9:57 AMDjuro
02/08/2024, 9:58 AMInputStream.read() function interruptible so that when it is cancelled it stops the readingDjuro
02/08/2024, 10:03 AMread(buffer) operation takes longer than 200msephemient
02/08/2024, 10:07 AMRobert Williams
02/08/2024, 10:55 AMRobert Williams
02/08/2024, 10:56 AMDjuro
02/08/2024, 10:58 AMbufferedReader and bufferedWriter from nio caused the same issue.Djuro
02/08/2024, 10:59 AMephemient
02/08/2024, 10:59 AMDjuro
02/08/2024, 10:59 AMephemient
02/08/2024, 11:00 AMDjuro
02/08/2024, 11:18 AMrunInterruptible doesn't make any difference, it works the same with and without it so I decided to just remove it and put yield() between read and write operations
It's just that runInterruptible doesn't work in this case. The only thing I can now assume is that what @Robert Williams said was right, the only way to interrupt it is to throw InterruptedException and since runInterruptible will throw (I assume) CancellationException it doesn't workJoffrey
02/08/2024, 12:10 PMrunInterruptible is useful for anything that actually supports interruption (e.g. Thread.sleep(), or BlockingQueue.take()). If your current coroutine is cancelled, the cancellation will be turned into an interruption of the thread for the code inside the runInterruptible lambda.
But if the code inside the lambda doesn't react to interruptions, it's pointless. It is just as pointless as cancelling a coroutine that's running non-cooperative (non-cancellable) code, like blocking code.Djuro
02/08/2024, 12:28 PMJoffrey
02/08/2024, 12:31 PMProcessBuilder with coroutines, I initially added some yield() between the standard stream reads. I then changed this to coroutineContext.ensureActive() to avoid unnecessary suspensions:
https://github.com/JetBrains/amper/blob/0.2/sources/cli/src/org/jetbrains/amper/processes/Processes.kt#L82Djuro
02/09/2024, 8:28 AMyield() since I don't really care about data transfered through these streamsJoffrey
02/09/2024, 8:45 AMDjuro
02/09/2024, 9:01 AMinputStream alive as much as possible so it's okay for yield to make it slower sometimes :DJoffrey
02/09/2024, 9:02 AMyield will also throw when cancelledDjuro
02/09/2024, 9:05 AMinputStream still open :DDjuro
02/09/2024, 9:07 AMwhile(!EOF){
read()
yield()
write
}
will not block the thread, while
while(!EOF){
read()
ensureActive()
write
}
will
For me it's important to have the input stream connection open, not to read/write from it 😄Joffrey
02/09/2024, 10:31 AM