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