[swift-users] Postponing owned object deinitialization

Nate Chandler nathaniel.chandler at gmail.com
Mon Feb 27 12:20:19 CST 2017


Hi Ole,

Thank you very much for your response.

I don't believe withExtendedLifetime can help out here.  The trouble is
that withExtendedLifetime only extends a lifetime until the end of a scope,
synchronously.

In my case, I want to extend the lifetime of Handle from AsyncHandle's
deinit until a closure enqueued asynchronously (from AsyncHandle's deinit)
is invoked.  Using withExtendedLifetime, I could only extend the lifetime
of Handle until the end of AsyncHandle's deinit method.

I want to write

class AsyncHandle {

    let handle: Handle

    deinit {
        let handle: Handle = self.handle
        q.async {
            letHandleDieNow(handle)
        }
    }

}

If I tried to use withExtendedLifetime, I could only write

class AsyncHandle {

    let handle: Handle

    deinit {
        let handle: Handle = self.handle
        withExtendedLifetime(handle) { handle in
            q.async {
                // This is where I want handle to finally be deinitialized
            }
        }
        // This is where handle is actually deinitialized, prior (probably)
to the invocation of the closure passed to async
    }

}

Please let me know if I am misunderstanding your suggestion or the
withExtendedLifetime API.

Thank you very much,
Nate Chandler


On Mon, Feb 27, 2017 at 12:31 PM Ole Begemann <ole at oleb.net> wrote:

> On 27/02/2017 15:17, Nate Chandler via swift-users wrote:
> > Hello all,
> >
> > I'm encountering a behavior around object lifetime and deinitialization
> > that is surprising to me.  Here's an approximation of what I'm
> encountering:
> >
> > I have a class Handle whose deinit must execute on a certain queue
> > (let's call it q--in my case it is a global queue).  I have a second
> > class AsyncHandle which owns a Handle and needs to be able to deinit on
> > any queue.  There's a tension to resolve between the deinitialization
> > contracts of Handle and AsyncHandle.  To resolve it, in AsyncHandle's
> > deinit, I am binding the owned instance of Handle to a local variable,
> > dispatching async onto the q, and from the async closure, calling
> > extendLifetime with the Handle, where extendLifetime is the following:
> >
> > @inline(never) func extendLifetime<T : AnyObject>() {}
> >
> > AsyncHandle's deinit looks like
> >
> > deinit {
> >     let handle = self.handle
> >     q.async {
> >         extendLifetime(handle)
> >     }
> > }
> >
> > This approach seems to work--the Handle gets deinit on q, the
> > appropriate queue.  Most of the time.  In the debugger, there is never a
> > problem.  Occasionally and inconsistently, on some devices, I am,
> > however, seeing a behavior that _seems_ to be the synchronous
> > deallocation of Handle from AsyncHandle's deinit on the queue that
> > AsyncHandle happens to be deinitializing on (not q).  If that is indeed,
> > the behavior I'm seeing, I do not understand why it is happening.
> >
> > A few questions:
> > (1) Given an object B owned (exclusively--no other objects have
> > references to A) by an object A, is it legal to extend the lifetime of B
> > in the deinit of A?  (It might conceivably not be legal if there is a
> > rule such as the following: when the runtime observes that an object R
> > referenced by a field of a deinitializing object O has a reference count
> > of one, it assumes that R must die when O dies and consequently puts R
> > into some moribund state from which there is no revivification.)
> > (2) If it is legal, is calling extendLifetime from a dispatch async the
> > appropriate way to do it?
> > (3) Is my "implementation" (such as it is) of extendLifetime correct?
> >  (I can't use the stdlib's _fixLifetime, unfortunately, or even
> > implement extendLifetime in the same way.)
>
> Have you tried using the standard library's withExtendedLifetime(_:_:)
> function?
>
> > (4) Does optimization based on visibility enter into this?  In my case
> > the AsyncHandle is fileprivate.
> > (5) Is there any entirely different approach to satisfy the following
> > requirements?  (a) AsyncHandle be releasable/deinitializable on any
> > thread.  (b) Handle be deinitialized only on some dispatch queue q.  (c)
> > AsyncHandle has the only reference to Handle.
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20170227/6428a3c6/attachment.html>


More information about the swift-users mailing list