[swift-users] Postponing owned object deinitialization
Nate Chandler
nathaniel.chandler at gmail.com
Mon Feb 27 16:21:44 CST 2017
Jordan,
Thank you very much for your response.
Your explanation of what the optimizer is free to do in the face of
@inline(never) was enlightening. It's clear that, as Ole was suggesting, I
need to make extendLifetime call through to the standard library's
withExtendedLifetime to prevent the optimizer from peeking:
func extendLifetime<T : AnyObject>(_ t: T) {
withExtendedLifetime(handle) {}
}
And thank you (very much) for calling out that race. I went ahead with the
change that you suggested, making AsyncHandle's Handle an IUO var which
gets nil'd prior to the call to async. AsyncHandle now looks like
class AsyncHandle {
var handle: Handle!
deinit {
let handle = self.handle
self.handle = nil
q.async {
extendLifetime(handle)
}
}
}
Thanks again,
Nate Chandler
On Mon, Feb 27, 2017 at 3:01 PM Jordan Rose <jordan_rose at apple.com> wrote:
>
> On Feb 27, 2017, at 10:53, Ole Begemann via swift-users <
> swift-users at swift.org> wrote:
>
> On 27/02/2017 19:34, Nate Chandler via swift-users wrote:
>
> Hi Ole,
>
> A quick follow-up--are you suggesting calling withExtendedLifetime
> inside the closure passed to async, as below?
>
> class AsyncHandle {
>
> let handle: Handle
>
> deinit {
> let handle: Handle = self.handle
> q.async {
> withExtendedLifetime(handle) {}
> }
> }
> }
>
>
> Yes, that's what I'm suggesting. Sorry I didn't make that clear before.
> Since you mentioned that you couldn't use the stdlib's _fixLifetime
> function, I just wanted to point out that there is a public function in the
> stdlib for this purpose.
>
> If so, it seems that that may be a final answer to (3). It does raise
> an additional question, however:
>
> (6) Would we expect calling withExtendedLifetime to have different
> behavior from calling an @inline(never) function from a closure enqueued
> async from deinit?
>
>
> Yeah, I don't know the answer, sorry.
>
>
> I'm not an optimizer person, but expecting '@inline(never)' to mean
> anything other than "don't inline this" is probably set for failure. The
> optimizer is still allowed to look at the body of the function.
> withExtendedLifetime is implemented more carefully to prevent eliding the
> capture.
>
> That said, if you're *not* on when the outer deinit gets called 'q', you
> still have a raceāit's possible that 'q' will execute the block you give it
> before the deinitializer exits! I don't think there's a good way to avoid
> this other than to make 'handle' optional (or ImplicitlyUnwrappedOptional)
> and explicitly set it to nil before enqueuing the "deallocation block".
>
> Jordan
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20170227/9b1a248e/attachment.html>
More information about the swift-users
mailing list