[swift-users] Postponing owned object deinitialization
Ole Begemann
ole at oleb.net
Mon Feb 27 11:31:50 CST 2017
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.
More information about the swift-users
mailing list