[swift-users] Postponing owned object deinitialization

Nate Chandler nathaniel.chandler at gmail.com
Mon Feb 27 08:17:03 CST 2017


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.)
(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.

Thank you very much,
Nate Chandler
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-users/attachments/20170227/1b16fd01/attachment.html>


More information about the swift-users mailing list