Reputation: 1766
Suppose I have an object that must explicitly call the close() function to ensure that all resources are released.
If this object is passed (e.g. through a channel or CompletableDeferred) and there is no guarantee that it will be received correctly by the receiver (e.g. risk of concurrency if the user does a Cancel), then obviously this object can only be GC'd because no one references it, but who is guaranteed that this close() will be called?
class TestLink(val address: String) {
val fd = openNativeResource(address)
private val _eventChannel = Channel<String>()
val incoming: ReceiveChannel<String> get() = _eventChannel
companion object {
suspend fun create(scope: CoroutineScope, address: String): TestLink {
val link = TestLink(address)
link.start(scope)
return link
}
}
fun start(scope: CoroutineScope) {
scope.launch {
while (true) {
val data = readNativeResource(fd)
if (data != null)
_eventChannel.send(data)
else
break
}
_eventChannel.close()
}
}
fun close() {
closeNativeResource(fd)
}
}
@Test
fun createLinkWithTimeout() = runBlocking {
val linkDeferred = CompletableDeferred<TestLink>()
val job = launch {
try {
val link = TestLink.create(this, "test")
linkDeferred.complete(link)
// run here, and timeout at the same time.
} catch (e: Exception) {
linkDeferred.completeExceptionally(e)
}
}
val link = withTimeoutOrNull(100) {
linkDeferred.await()
}
if (link != null) {
var counter = 0
for (data in link.incoming) {
counter++
if (counter >= 100) break
println(data)
}
link.close()
} else {
job.cancelAndJoin()
}
}
Upvotes: 0
Views: 28