[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